Let's Encrypt & ACME Protocol Guide

Complete guide to free SSL/TLS certificates with Let's Encrypt and the ACME protocol

🌐 What is Let's Encrypt?

Let's Encrypt is a free, automated, and open Certificate Authority (CA) that provides SSL/TLS certificates trusted by all major browsers. It uses the ACME (Automatic Certificate Management Environment) protocol to automate certificate issuance and renewal.

Key benefits

  • Free: No cost for certificates (domain validation only)
  • Automated: ACME protocol enables automatic issuance and renewal
  • Trusted: Certificates trusted by 99%+ of browsers
  • Secure: Modern security standards, 90-day validity encourages automation
  • Open: Open source tools and transparent operations

Certificate types supported

  • Single domain (example.com)
  • Multiple domains / SAN certificates (up to 100 domains)
  • Wildcard certificates (*.example.com)
  • ECDSA and RSA key types

What's NOT supported

  • Organization Validation (OV) certificates
  • Extended Validation (EV) certificates
  • Email certificates (S/MIME)
  • Code signing certificates
  • Certificates valid for longer than 90 days

šŸ” ACME Challenge Types

To prove you control a domain, Let's Encrypt requires you to complete a challenge. There are three types:

HTTP-01 Challenge

How it works: Let's Encrypt requests a file at http://your-domain/.well-known/acme-challenge/TOKEN

āœ… Pros:

  • Easy to automate with web servers
  • Works with standard HTTP on port 80
  • No DNS configuration needed
  • Most common and recommended for single domains

āŒ Cons:

  • Requires port 80 to be accessible from internet
  • Cannot be used for wildcard certificates
  • Doesn't work if port 80 is blocked by firewall

Use when: You have a public web server and want single or multi-domain certificates.

DNS-01 Challenge

How it works: Create a TXT record at _acme-challenge.your-domain with a specific value

āœ… Pros:

  • Works for wildcard certificates (*.example.com)
  • No need for public web server
  • Works behind firewalls
  • Can validate internal/private domains

āŒ Cons:

  • Requires DNS provider API access for automation
  • More complex to set up initially
  • DNS propagation can cause delays (up to 2 hours)
  • API credentials need secure storage

Use when: You need wildcard certificates or server is not publicly accessible.

TLS-ALPN-01 Challenge

How it works: Validation via TLS connection on port 443 using ALPN extension

āœ… Pros:

  • Works when port 80 is blocked but 443 is open
  • No DNS configuration needed
  • Faster than DNS-01 (no propagation delay)

āŒ Cons:

  • Cannot be used for wildcard certificates
  • Less client support (not all ACME clients support it)
  • More complex to implement

Use when: Port 80 is blocked but you need automated certificates without DNS.

🌟 Wildcard Certificates

What are wildcard certificates?

A wildcard certificate covers all subdomains at one level. For example, *.example.com covers:

  • www.example.com
  • api.example.com
  • blog.example.com

But NOT: example.com (apex domain) or subdomain.api.example.com (nested subdomain)

How to get wildcard certificates

# Using certbot with DNS challenge (example: Cloudflare)
certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
  -d example.com \
  -d "*.example.com"

# Using acme.sh with DNS challenge
acme.sh --issue \
  --dns dns_cloudflare \
  -d example.com \
  -d "*.example.com"

āš ļø Note: Wildcard certificates REQUIRE DNS-01 challenge. HTTP-01 and TLS-ALPN-01 won't work.

Best practices for wildcards

  • Always include both apex domain and wildcard: -d example.com -d "*.example.com"
  • Use DNS provider with good API support for automation
  • Store DNS API credentials securely (not in code)
  • Consider using specific subdomains instead if you only need a few
  • Monitor certificate expiry (90 days validity)

Supported DNS providers

Popular providers with ACME client support:

  • Cloudflare (certbot-dns-cloudflare)
  • Route 53 (certbot-dns-route53)
  • Google Cloud DNS (certbot-dns-google)
  • DigitalOcean (certbot-dns-digitalocean)
  • Namecheap, GoDaddy, and 100+ others via acme.sh

āš ļø Rate Limits

Let's Encrypt has rate limits to prevent abuse and ensure fair usage. These limits reset on a rolling basis.

Main rate limits

  • Certificates per Registered Domain: 50 per week
    Example: 50 certificates for *.example.com, www.example.com, etc. per week
  • Duplicate Certificate: 5 per week
    Same exact set of domains counts as duplicate
  • Failed Validations: 5 per account, per hostname, per hour
    Too many failed challenges will temporarily block issuance
  • Accounts per IP: 10 per 3 hours
    Limit on creating new ACME accounts
  • Pending Authorizations: 300 per account
    Challenges waiting for validation

How to avoid hitting limits

  • Use staging environment for testing (--staging flag)
  • Don't recreate identical certificates (cache them instead)
  • Use multi-domain certificates instead of many single-domain certs
  • Fix validation issues before retrying (check logs)
  • Monitor expiry and renew 30 days before expiration
  • Coordinate with team to avoid duplicate requests

Testing with staging environment

# Certbot staging
certbot certonly --staging -d example.com

# acme.sh staging
acme.sh --issue --staging -d example.com -w /var/www/html

# Once working, use production (remove --staging)

Staging environment has much higher rate limits (same limits Ɨ 1000) but issues certificates from a test CA (not trusted by browsers).

Check your rate limit status

Visit crt.sh and search for your domain to see all issued certificates.

https://crt.sh/?q=example.com

šŸ”„ Certificate Renewal & Automation

Why 90-day validity?

Let's Encrypt certificates are valid for 90 days (not configurable). This is intentional to:

  • Encourage automation (manual renewal 4Ɨ per year is tedious)
  • Limit damage from compromised private keys
  • Reduce impact of mis-issued certificates
  • Enable agile security improvements

Renewal timing

Recommended renewal schedule:

  • 30 days before expiry: Standard renewal window (certbot default)
  • 60 days: Certificate still has 30 days validity remaining
  • 15-7 days: Fallback/backup renewal attempts
  • Never: Wait until last day (no room for errors)

Automatic renewal with certbot

# Test renewal (dry run)
certbot renew --dry-run

# Renew all certificates (only renews if <30 days to expiry)
certbot renew

# Force renewal of specific certificate
certbot renew --cert-name example.com --force-renewal

Certbot installs a systemd timer (or cron job) that runs twice daily to check for renewals.

Check certbot renewal timer (systemd)

# Check if timer is active
systemctl status certbot.timer

# View timer schedule
systemctl list-timers certbot.timer

# Manually trigger renewal check
systemctl start certbot.service

Automatic renewal with acme.sh

# acme.sh installs a cron job automatically
# Check cron installation
crontab -l | grep acme.sh

# Manually trigger renewal check (only renews if <60 days to expiry)
acme.sh --renew-all

# Force renewal
acme.sh --renew -d example.com --force

Post-renewal hooks

After renewal, you often need to reload/restart services to use the new certificate:

# Certbot: Add deploy hook
certbot renew --deploy-hook "systemctl reload nginx"

# Or in renewal config: /etc/letsencrypt/renewal/example.com.conf
renew_hook = systemctl reload nginx

# acme.sh: Add reloadcmd
acme.sh --install-cert -d example.com \
  --cert-file /etc/nginx/certs/cert.pem \
  --key-file /etc/nginx/certs/key.pem \
  --fullchain-file /etc/nginx/certs/fullchain.pem \
  --reloadcmd "systemctl reload nginx"

Monitoring certificate expiry

  • Set up monitoring alerts (30, 7, 1 days before expiry)
  • Use external monitoring: SSL Labs, Uptime Robot, StatusCake
  • Check renewal logs regularly
  • Test renewal process quarterly

šŸ”§ Common Issues & Solutions

"too many certificates already issued for: example.com"

Problem: Hit the 50 certificates per week limit

Solutions:

  • Wait 7 days for rate limit reset (it's a rolling window)
  • Reuse existing certificates instead of creating new ones
  • Combine multiple domains into one certificate (SAN)
  • Check crt.sh to see what certificates were issued

"Connection refused" or "Timeout" during HTTP-01 challenge

Problem: Let's Encrypt can't reach your web server on port 80

Solutions:

  • Verify port 80 is open: nc -zv your-domain 80
  • Check firewall rules (ufw, iptables, cloud provider security groups)
  • Verify DNS points to correct IP: dig your-domain
  • Ensure web server is running and serving .well-known directory
  • Consider using DNS-01 challenge if port 80 can't be opened

DNS-01 challenge not working

Problem: TXT record not found or incorrect

Solutions:

  • Verify TXT record: dig _acme-challenge.example.com TXT
  • Wait for DNS propagation (can take 2-120 minutes)
  • Check DNS provider API credentials are correct
  • Some DNS providers need special permissions for TXT records
  • Test with staging environment first

Certificate not trusted in browser

Problem: Browser shows "Not Secure" warning

Solutions:

  • Verify certificate is from production (not staging)
  • Check certificate dates (not expired, not future-dated)
  • Ensure certificate includes correct domain names
  • Install full certificate chain (not just leaf certificate)
  • Check for mixed content (loading HTTP resources on HTTPS page)

"Renewal failed" errors

Problem: Automatic renewal is failing

Solutions:

  • Check logs: /var/log/letsencrypt/letsencrypt.log
  • Test renewal manually: certbot renew --dry-run
  • Verify cron/systemd timer is running
  • Check for configuration changes since last successful renewal
  • Ensure server has internet access to Let's Encrypt API

āœ… Best Practices

Certificate management

  • Always test with --staging or --dry-run first
  • Set up automatic renewal (don't rely on manual processes)
  • Use post-renewal hooks to reload services automatically
  • Keep ACME client (certbot/acme.sh) updated
  • Back up certificates and account keys

Security

  • Protect account private key (/etc/letsencrypt/accounts/)
  • Use ECDSA certificates for better performance (optional)
  • Enable OCSP stapling in web server config
  • Set proper file permissions (600 for keys, 644 for certs)
  • Use HSTS header after confirming HTTPS works

Monitoring

  • Set up expiry alerts (30, 7, 1 days before expiration)
  • Monitor renewal logs for failures
  • Use external monitoring services (SSL Labs, StatusCake)
  • Document your renewal process for team
  • Test disaster recovery (certificate re-issuance)

Production deployment

  • Use DNS-01 for wildcard certificates
  • Use HTTP-01 for simple single/multi-domain certificates
  • Combine multiple subdomains into one certificate when possible
  • Keep renewal buffer time (renew 30 days before expiry)
  • Have backup plan if Let's Encrypt is down (cached certificates valid for days/weeks)

šŸ”— Certificate Chain Structure

Let's Encrypt certificate hierarchy

Let's Encrypt uses a two-tier hierarchy with ISRG (Internet Security Research Group) root certificates:

ISRG Root X1 (RSA 4096, expires 2035)
└── R3 (RSA 2048, intermediate CA)
    └── Your Certificate (leaf)

ISRG Root X2 (ECDSA P-384, expires 2035)
ā”œā”€ā”€ R10 (ECDSA P-384, intermediate CA)
│   └── Your Certificate (leaf, ECDSA)
└── R11 (ECDSA P-384, intermediate CA)
    └── Your Certificate (leaf, ECDSA)
  • R3: Current RSA intermediate (most common)
  • R10/R11: ECDSA intermediates for ECDSA certificates
  • ISRG Root X1: Trusted by all major browsers since 2016
  • ISRG Root X2: ECDSA root for future-proofing

Cross-signing and compatibility

Let's Encrypt certificates are trusted by 99%+ of browsers, including:

  • Chrome 50+ (April 2016)
  • Firefox 50+ (November 2016)
  • Safari 10+ (macOS 10.12+, iOS 10+)
  • Edge (all versions)
  • Android 7.1.1+ (January 2017)
  • Windows 10+ (built-in trust)

āš ļø Legacy compatibility: Android 7.0 and older require special configuration. As of September 2021, Let's Encrypt stopped cross-signing with DST Root CA X3, which may affect very old devices.

Verify certificate chain

# Check certificate chain from your server
openssl s_client -connect example.com:443 -servername example.com

# Verify chain locally
openssl verify -CAfile chain.pem cert.pem

# View full chain details
openssl s_client -connect example.com:443 -showcerts

šŸŒ Alternative ACME Certificate Authorities

While Let's Encrypt is the most popular, other CAs also support the ACME protocol:

ZeroSSL

  • Free certificates with 90-day validity
  • ACME support via acme.sh and certbot
  • Web dashboard for certificate management
  • Commercial plans available for extended validation
# Use with acme.sh
acme.sh --set-default-ca --server zerossl
acme.sh --issue -d example.com -w /var/www/html

Buypass Go SSL

  • Free certificates with 180-day validity (longer than Let's Encrypt)
  • Based in Norway, follows EU data regulations
  • ACME support available
  • Good alternative for European deployments
# Use with certbot
certbot certonly \
  --server https://api.buypass.com/acme/directory \
  -d example.com

# Use with acme.sh
acme.sh --set-default-ca --server buypass
acme.sh --issue -d example.com -w /var/www/html

Google Trust Services

  • Public ACME CA launched in 2022
  • 90-day certificate validity
  • Integration with Google Cloud Platform
  • Enterprise-grade infrastructure
# Use with certbot
certbot certonly \
  --server https://dv.acme-v02.api.pki.goog/directory \
  -d example.com

Choosing an ACME CA

CAValidityBest For
Let's Encrypt90 daysMost deployments, best ecosystem
ZeroSSL90 daysDashboard UI, commercial options
Buypass180 daysLonger validity, EU compliance
Google Trust90 daysGCP integration, enterprise needs

šŸ› ļø Popular ACME Clients

Certbot (official)

  • Official EFF client, most popular
  • Written in Python
  • Excellent documentation
  • Many plugins for DNS providers and web servers
  • Best for: Beginners, standard deployments

acme.sh

  • Pure shell script (bash), no dependencies
  • Supports 100+ DNS providers
  • Lightweight and fast
  • Best for: Automated environments, minimal systems

Caddy web server

  • Built-in automatic HTTPS with Let's Encrypt
  • Zero configuration needed
  • Handles issuance and renewal automatically
  • Best for: New deployments, simple setups

Traefik reverse proxy

  • Built-in Let's Encrypt support
  • Automatic certificate management
  • Great for container/microservices
  • Best for: Docker, Kubernetes environments

šŸ“š Additional Resources