Let's Encrypt - Advanced

Cheatsheet Certificate

Advanced Let's Encrypt features including Docker, monitoring, best practices, and production deployment

Docker - Standalone Mode

Run Certbot in Docker container for certificate issuance.

docker run -it --rm \
  -v /etc/letsencrypt:/etc/letsencrypt \
  -v /var/lib/letsencrypt:/var/lib/letsencrypt \
  -p 80:80 \
  certbot/certbot certonly --standalone -d example.com

Note: Port 80 must be available on host.

Docker - Compose Setup

Docker Compose configuration for automatic renewal.

services:
  certbot:
    image: certbot/certbot
    volumes:
      - /etc/letsencrypt:/etc/letsencrypt
      - /var/lib/letsencrypt:/var/lib/letsencrypt
    command: renew

Run renewal:

docker-compose run --rm certbot renew

Docker - Nginx with Certbot

Complete setup with Nginx and automated renewals.

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /etc/letsencrypt:/etc/letsencrypt:ro
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    restart: unless-stopped

  certbot:
    image: certbot/certbot
    volumes:
      - /etc/letsencrypt:/etc/letsencrypt
      - /var/lib/letsencrypt:/var/lib/letsencrypt
      - ./webroot:/var/www/certbot
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

Advanced - Custom Key Size

Generate certificate with 4096-bit RSA key.

sudo certbot certonly --rsa-key-size 4096 -d example.com

Options:

  • 2048 (default, recommended)
  • 4096 (more secure, slower)

Advanced - Elliptic Curve Keys

Use ECDSA instead of RSA for better performance.

sudo certbot certonly --key-type ecdsa --elliptic-curve secp384r1 -d example.com

Curves available:

  • secp256r1 (default)
  • secp384r1 (recommended)
  • secp521r1

Advanced - OCSP Stapling

Enable OCSP stapling for better SSL performance.

Nginx configuration:

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

Apache configuration:

SSLUseStapling on
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"

Advanced - HSTS Headers

Enable HTTP Strict Transport Security.

Nginx:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

Apache:

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

Note: Only enable after confirming HTTPS works perfectly.

Best Practices - Security Checklist

Production SSL security checklist.

Certificate:

  • Use fullchain.pem (not cert.pem alone)
  • Enable OCSP stapling
  • Test with SSL Labs (A+ rating)

Web Server:

  • Set strong SSL ciphers
  • Disable SSLv3, TLS 1.0, TLS 1.1
  • Enable HSTS headers
  • Redirect all HTTP to HTTPS

Testing:

# Test SSL configuration
sudo nginx -t
sudo apachectl configtest

# Test HTTPS
curl -I https://example.com

Best Practices - Renewal Strategy

Automatic renewal best practices.

Checklist:

  • Enable auto-renewal timer (systemctl enable certbot.timer)
  • Monitor certificate expiry (renew at 60 days)
  • Set up email/Slack alerts
  • Test renewal monthly with --dry-run
  • Keep logs for at least 90 days

Schedule:

  • Let’s Encrypt certs valid for 90 days
  • Auto-renewal runs twice daily
  • Renewal triggers at 30 days before expiry

Best Practices - Production Tips

Production deployment recommendations.

Load Balancers:

  • Install certificates on origin servers
  • Terminate SSL at load balancer OR origin (not both)
  • Use health checks on port 443

Cloudflare:

  • Use “Full” or “Full (Strict)” SSL mode
  • Install origin certificate on server
  • Ensure port 80 reachable for HTTP challenge

Multi-Server:

  • Use DNS-01 challenge (no port 80 needed)
  • Share certificates via NFS or copy manually
  • Consider centralized certificate management

Rate Limits:

  • Max 50 certificates per registered domain/week
  • Plan domain naming accordingly
  • Use staging for testing

Monitoring - Certificate Expiry

Check certificate expiration from command line.

echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -enddate

Output: notAfter=Dec 13 12:00:00 2025 GMT

Monitoring - Days Until Expiry

Calculate days remaining until expiration.

echo $(( ($(date -d "$(openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -enddate | cut -d= -f2)" +%s) - $(date +%s)) / 86400 ))

Output: Number of days (e.g., 60)

Monitoring - Alert Script

Automated monitoring script for certificate expiry.

#!/bin/bash
DOMAIN="example.com"
CERT_PATH="/etc/letsencrypt/live/$DOMAIN/cert.pem"
ALERT_DAYS=30

# Calculate days until expiry
EXPIRY_DATE=$(openssl x509 -in $CERT_PATH -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s)
CURRENT_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $CURRENT_EPOCH) / 86400 ))

# Alert if expiring soon
if [ $DAYS_LEFT -lt $ALERT_DAYS ]; then
  echo "WARNING: Certificate for $DOMAIN expires in $DAYS_LEFT days"
  # Send alert (email, Slack, etc.)
fi

Monitoring - Slack Webhook Alert

Send Slack notifications for expiring certificates.

#!/bin/bash
DOMAIN="example.com"
SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
DAYS_LEFT=$(echo $(( ($(date -d "$(openssl x509 -in /etc/letsencrypt/live/$DOMAIN/cert.pem -noout -enddate | cut -d= -f2)" +%s) - $(date +%s)) / 86400 )))

if [ $DAYS_LEFT -lt 30 ]; then
  curl -X POST -H 'Content-type: application/json' \
    --data "{\"text\":\"⚠️ SSL certificate for $DOMAIN expires in $DAYS_LEFT days\"}" \
    $SLACK_WEBHOOK
fi

Schedule with cron (daily check):

0 9 * * * /path/to/cert-monitor.sh

Monitoring - Prometheus Exporter

Monitor certificates with Prometheus.

Install ssl_exporter:

docker run -d -p 9219:9219 ribbybibby/ssl-exporter:latest

Prometheus config:

scrape_configs:
  - job_name: 'ssl'
    metrics_path: /probe
    static_configs:
      - targets:
        - example.com:443
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: localhost:9219

Advanced - Rate Limit Management

Understand and work with Let’s Encrypt rate limits.

Main limits:

  • 50 certificates per registered domain per week
  • 5 duplicate certificates per week
  • 300 new orders per account per 3 hours
  • 10 accounts per IP per 3 hours

Check current usage:

# List all certificates
sudo certbot certificates

# Count certificates for a domain
sudo certbot certificates | grep -c "example.com"

Strategies:

  • Use staging environment for testing (--staging)
  • Plan domain structure carefully
  • Renew before 30-day window
  • Delete unused certificates

Advanced - Wildcard Best Practices

Optimize wildcard certificate usage.

Single wildcard covers all subdomains:

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
  -d example.com -d '*.example.com'

Benefits:

  • One certificate for unlimited subdomains
  • Easier management
  • Lower rate limit usage

Considerations:

  • Requires DNS-01 challenge
  • Root domain must be included separately
  • More sensitive (secure private key carefully)

Advanced - Certificate Pinning

Implement HTTP Public Key Pinning (deprecated, use with caution).

Extract public key:

openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -pubkey -noout | \
  openssl pkey -pubin -outform der | \
  openssl dgst -sha256 -binary | \
  base64

Note: HPKP is deprecated. Use Certificate Transparency monitoring instead.