Let’s Encrypt (Certbot)
Installation
Ubuntu/Debian
# Update system
sudo apt update
# Install Certbot
sudo apt install certbot python3-certbot-nginx python3-certbot-apache -y
# Verify installation
certbot --versionCentOS/RHEL
# Install Certbot
sudo yum install certbot python3-certbot-nginx -y
# Verify installation
certbot --versionCreate SSL Certificate
Standalone (Without Running Web Server)
# Stop web server (if running)
sudo systemctl stop nginx
# Or for Apache
sudo systemctl stop apache2
# Create certificate (interactive)
sudo certbot certonly --standalone
# Or non-interactive
sudo certbot certonly --standalone \
-d domain.com \
-d www.domain.com \
-m [email protected] \
--agree-tos \
--non-interactive
# Restart web server
sudo systemctl start nginxNginx Plugin (Recommended)
# Create certificate with Nginx plugin
sudo certbot certonly --nginx \
-d domain.com \
-d www.domain.com \
-m [email protected] \
--agree-tos
# Or interactive
sudo certbot certonly --nginxApache Plugin
# Create certificate with Apache plugin
sudo certbot certonly --apache \
-d domain.com \
-d www.domain.com \
-m [email protected] \
--agree-tosWebroot (For Already Running Server)
# Create certificate
sudo certbot certonly --webroot \
-w /var/www/html \
-d domain.com \
-d www.domain.com
# For multiple domains with different roots
sudo certbot certonly --webroot \
-w /var/www/domain1.com -d domain1.com \
-w /var/www/domain2.com -d domain2.comCertificate Location
# Certificate location
/etc/letsencrypt/live/domain.com/
# Full chain
/etc/letsencrypt/live/domain.com/fullchain.pem
# Private key
/etc/letsencrypt/live/domain.com/privkey.pem
# Certificate only
/etc/letsencrypt/live/domain.com/cert.pem
# Chain only
/etc/letsencrypt/live/domain.com/chain.pem
# All files are symlinks to actual files in /etc/letsencrypt/archiveNginx Configuration
server {
listen 443 ssl http2;
server_name domain.com www.domain.com;
ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
# SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers HIGH:!aNULL:!MD5;
# Rest of configuration
root /var/www/domain.com/public;
index index.php index.html;
location / {
# Your configuration
}
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name domain.com www.domain.com;
return 301 https://$server_name$request_uri;
}Apache Configuration
<VirtualHost *:443>
ServerName domain.com
ServerAlias www.domain.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/domain.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/domain.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/domain.com/chain.pem
# Rest of configuration
DocumentRoot /var/www/domain.com/public
</VirtualHost>
# Redirect HTTP to HTTPS
<VirtualHost *:80>
ServerName domain.com
ServerAlias www.domain.com
Redirect permanent / https://domain.com/
</VirtualHost>Automatic Renewal
Systemd Timer (Automatic)
# Check renewal status
sudo certbot renew --dry-run
# Start renewal service
sudo systemctl start certbot.timer
sudo systemctl enable certbot.timer
# Check timer status
sudo systemctl status certbot.timer
sudo systemctl list-timers certbot.timerManual Renewal
# Renew all certificates
sudo certbot renew
# Renew specific certificate
sudo certbot renew --cert-name domain.com
# Force renewal
sudo certbot renew --force-renewalCron Job (Manual Renewal)
# Edit crontab
EDITOR=nano crontab -e
# Add renewal cron (runs daily at 2:30 AM)
30 2 * * * sudo certbot renew --post-hook "systemctl reload nginx" >> /var/log/le-renew.log 2>&1
# For Apache
30 2 * * * sudo certbot renew --post-hook "systemctl reload apache2" >> /var/log/le-renew.log 2>&1
# Or with pre-hook and post-hook
30 2 * * * sudo certbot renew --pre-hook "systemctl stop nginx" --post-hook "systemctl start nginx" >> /var/log/le-renew.log 2>&1Renew Hooks
# Pre-renewal hook (stop service)
certbot renew --pre-hook "systemctl stop nginx"
# Post-renewal hook (restart service)
certbot renew --post-hook "systemctl reload nginx"
# Both hooks
certbot renew --pre-hook "systemctl stop nginx" --post-hook "systemctl start nginx"
# Renew all with hooks
sudo certbot renew --post-hook "systemctl reload nginx"Certificate Management
List Certificates
# List all certificates
sudo certbot certificates
# Show certificate details
sudo certbot show domain.comRenew Specific Certificate
# Renew one certificate
sudo certbot renew --cert-name domain.comDelete Certificate
# Delete certificate
sudo certbot delete --cert-name domain.comExpand Certificate (Add Domains)
# Add domains to existing certificate
sudo certbot certonly --nginx --cert-name domain.com -d domain.com -d www.domain.com -d new-domain.comTroubleshooting
# Test renewal (dry-run)
sudo certbot renew --dry-run -v
# Check certificate info
sudo openssl x509 -text -noout -in /etc/letsencrypt/live/domain.com/cert.pem
# Check expiration
sudo openssl x509 -enddate -noout -in /etc/letsencrypt/live/domain.com/cert.pem
# View renewal log
tail -f /var/log/letsencrypt/letsencrypt.log
# View renewal status
systemctl status certbot.timer
# Check for renewal errors
journalctl -u certbot.serviceRate Limits
# Let's Encrypt rate limits:
# - 50 certificates per domain per week
# - 5 certificates per domain per week (duplicates)
# - 5 failures per account per hour
# Use staging environment for testing
sudo certbot certonly --staging --nginx -d domain.com
# Check rate limit status
# https://crt.sh/?q=domain.comRenewal Notifications
# Certbot emails notifications when certificate expires in 20 days
# Set email in configuration file:
sudo nano /etc/letsencrypt/renewal/domain.com.conf
# Or update existing
sudo certbot update_account --email [email protected]