Let's Encrypt Complete Guide 2025: Free SSL Certificates
Let's Encrypt has revolutionized web security by providing free, automated SSL/TLS certificates to millions of websites. This comprehensive guide covers everything you need to know about using Let's Encrypt in 2025, from basic installation to advanced automation and wildcard certificates.
What is Let's Encrypt?
Let's Encrypt is a free, automated, and open Certificate Authority (CA) that provides SSL/TLS certificates at no cost. Launched in 2016, it has issued over 3 billion certificates and secured more than 300 million websites worldwide.
Key Features
- 100% Free: No cost for certificates, renewals, or support
- Automated: ACME protocol enables automatic issuance and renewal
- Secure: Industry-standard encryption, trusted by all major browsers
- Transparent: All certificates logged in Certificate Transparency logs
- Open: Open source tools and protocols
- Wildcard Support: Free wildcard certificates for subdomains
Installing Certbot
Ubuntu/Debian
# Update package list
sudo apt update
# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Or for Apache
sudo apt install certbot python3-certbot-apache
CentOS/RHEL
# Enable EPEL repository
sudo yum install epel-release
# Install Certbot
sudo yum install certbot python3-certbot-nginx
# Or for Apache
sudo yum install certbot python3-certbot-apache
Using Snap (Recommended)
# Install snapd
sudo apt install snapd
# Install Certbot via snap
sudo snap install --classic certbot
# Create symlink
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Obtaining Your First Certificate
Automatic Configuration (Nginx)
# Automatic Nginx configuration
sudo certbot --nginx -d example.com -d www.example.com
# Certbot will:
# 1. Obtain certificate
# 2. Configure Nginx automatically
# 3. Set up HTTPS redirect
# 4. Enable automatic renewal
Automatic Configuration (Apache)
# Automatic Apache configuration
sudo certbot --apache -d example.com -d www.example.com
# Certbot handles everything automatically
Manual Certificate Only
# Get certificate without auto-configuration
sudo certbot certonly --webroot \
-w /var/www/html \
-d example.com \
-d www.example.com \
--email admin@example.com \
--agree-tos \
--non-interactive
# Certificates saved to:
# /etc/letsencrypt/live/example.com/fullchain.pem
# /etc/letsencrypt/live/example.com/privkey.pem
Wildcard Certificates
DNS-01 Challenge Required
Wildcard certificates require DNS validation. Install DNS plugin for your provider:
# Cloudflare
sudo apt install python3-certbot-dns-cloudflare
# Create credentials file
mkdir -p ~/.secrets
cat > ~/.secrets/cloudflare.ini << EOF
dns_cloudflare_api_token = YOUR_API_TOKEN
EOF
chmod 600 ~/.secrets/cloudflare.ini
# Request wildcard certificate
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
-d example.com \
-d *.example.com \
--email admin@example.com \
--agree-tos
Supported DNS Providers
| Provider | Plugin | Installation |
|---|---|---|
| Cloudflare | certbot-dns-cloudflare | apt install python3-certbot-dns-cloudflare |
| AWS Route53 | certbot-dns-route53 | apt install python3-certbot-dns-route53 |
| Google Cloud DNS | certbot-dns-google | apt install python3-certbot-dns-google |
| DigitalOcean | certbot-dns-digitalocean | apt install python3-certbot-dns-digitalocean |
Automatic Renewal
Testing Renewal
# Dry run (test without actually renewing)
sudo certbot renew --dry-run
# If successful, automatic renewal is configured
Renewal Configuration
# Check systemd timer status
sudo systemctl status certbot.timer
# Enable timer if not active
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer
# Manual renewal (if needed)
sudo certbot renew
# Force renewal
sudo certbot renew --force-renewal
Renewal Hooks
# Create post-renewal hook
sudo nano /etc/letsencrypt/renewal-hooks/post/reload-services.sh
#!/bin/bash
systemctl reload nginx
systemctl reload apache2
echo "Services reloaded after certificate renewal"
# Make executable
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/reload-services.sh
Manual Nginx Configuration
# /etc/nginx/sites-available/example.com
# HTTP to HTTPS redirect
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
# HTTPS configuration
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# SSL certificates
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
# Enable site
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Manual Apache Configuration
# /etc/apache2/sites-available/example.com-ssl.conf
ServerName example.com
ServerAlias www.example.com
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/html
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite HIGH:!aNULL:!MD5
SSLHonorCipherOrder on
# OCSP Stapling
SSLUseStapling on
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
# Security headers
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
# Enable modules and site
sudo a2enmod ssl rewrite headers
sudo a2ensite example.com-ssl
sudo apache2ctl configtest
sudo systemctl reload apache2
Rate Limits
⚠️ Let's Encrypt Rate Limits
- Certificates per Domain: 50 per week
- Duplicate Certificates: 5 per week
- Failed Validations: 5 per account per hostname per hour
- Accounts per IP: 10 per 3 hours
- Pending Authorizations: 300 per account
Use staging environment for testing to avoid hitting limits!
Using Staging Environment
# Test with staging server (doesn't count against rate limits)
sudo certbot certonly --staging \
--nginx \
-d example.com \
-d www.example.com
# Once working, get production certificate
sudo certbot certonly \
--nginx \
-d example.com \
-d www.example.com
Advanced Features
Multiple Domains (SAN)
# Single certificate for multiple domains
sudo certbot certonly --nginx \
-d example.com \
-d www.example.com \
-d blog.example.com \
-d shop.example.com \
-d api.example.com
Certificate Expansion
# Add new domain to existing certificate
sudo certbot certonly --nginx \
-d example.com \
-d www.example.com \
-d blog.example.com \
-d newdomain.example.com \
--expand
Certificate Revocation
# Revoke certificate
sudo certbot revoke --cert-path /etc/letsencrypt/live/example.com/cert.pem
# Revoke and delete
sudo certbot revoke --cert-path /etc/letsencrypt/live/example.com/cert.pem --delete-after-revoke
Troubleshooting
Common Issues
Port 80 Not Accessible
# Check if port 80 is open
sudo netstat -tlnp | grep :80
# Check firewall
sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Test from external
curl -I http://example.com/.well-known/acme-challenge/test
DNS Not Propagated
# Check DNS
dig example.com +short
nslookup example.com
# Wait for DNS propagation (up to 48 hours)
# Use DNS checker: https://dnschecker.org/
Webroot Not Found
# Verify webroot path
ls -la /var/www/html/.well-known/acme-challenge/
# Create if missing
sudo mkdir -p /var/www/html/.well-known/acme-challenge/
sudo chown -R www-data:www-data /var/www/html/.well-known/
Best Practices
Security Recommendations
- Always use fullchain.pem (includes intermediates)
- Enable OCSP stapling for better performance
- Implement HSTS with preload
- Use TLS 1.2 and 1.3 only
- Configure strong cipher suites
- Set up automatic renewal monitoring
- Test renewal process regularly
Monitoring and Alerts
#!/bin/bash
# Monitor certificate expiration
DOMAIN="example.com"
ALERT_DAYS=14
EXPIRY=$(echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:443 2>/dev/null | \
openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
CURRENT_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $CURRENT_EPOCH) / 86400 ))
if [ $DAYS_LEFT -lt $ALERT_DAYS ]; then
echo "WARNING: Certificate expires in $DAYS_LEFT days"
# Send email/slack notification
fi
Conclusion
Let's Encrypt has made SSL/TLS certificates accessible to everyone, removing cost barriers and simplifying deployment. By following this guide, you can secure your website with free, trusted certificates and maintain them with automated renewal. The combination of Certbot's automation and Let's Encrypt's reliability makes HTTPS deployment straightforward and maintainable.
Verify Your Let's Encrypt Certificate
Use our free tools to check your installation:
- SSL Certificate Checker - Verify certificate installation
- SSL Chain Checker - Check certificate chain
- SSL Expiry Checker - Monitor expiration