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.