Let's Encrypt: Complete Setup Guide

How to get free SSL certificates with Let's Encrypt. Covers certbot setup, automatic renewal, HTTP-01 and DNS-01 validation, wildcard certificates, and common issues.


What Is Let's Encrypt?

Let's Encrypt is a free, automated Certificate Authority. It issues Domain Validation (DV) certificates that are trusted by all major browsers. Over 300 million websites use Let's Encrypt certificates.

Key facts: - Free -- no cost, ever - Automated -- certificates are issued and renewed via the ACME protocol - 90-day validity -- shorter than commercial certs, but auto-renewal handles it - Rate limited -- 50 certificates per registered domain per week

Install Certbot

Certbot is the most popular ACME client for Let's Encrypt.

Ubuntu/Debian

sudo apt update
sudo apt install certbot

With nginx plugin

sudo apt install certbot python3-certbot-nginx

With Apache plugin

sudo apt install certbot python3-certbot-apache

macOS

brew install certbot

Docker

docker run -it --rm \
    -v "/etc/letsencrypt:/etc/letsencrypt" \
    -v "/var/www/certbot:/var/www/certbot" \
    certbot/certbot certonly

Get Your First Certificate

Automatic (nginx)

The easiest method. Certbot modifies your nginx config automatically:

sudo certbot --nginx -d example.com -d www.example.com

Automatic (Apache)

sudo certbot --apache -d example.com -d www.example.com

Manual (HTTP-01)

If you want to handle the web server config yourself:

sudo certbot certonly --webroot -w /var/www/html \
    -d example.com -d www.example.com

This creates a file in /var/www/html/.well-known/acme-challenge/ that Let's Encrypt checks to verify you control the domain.

Manual (DNS-01)

Required for wildcard certificates. Certbot tells you to create a DNS TXT record:

sudo certbot certonly --manual --preferred-challenges dns \
    -d "*.example.com" -d "example.com"

Certbot will display something like:

Please deploy a DNS TXT record under the name:
_acme-challenge.example.com
with the following value:
gfj9Xq...Rg85nM

Add this TXT record at your DNS provider, wait for propagation, then press Enter.

You can also use our Let's Encrypt page which handles the ACME flow through a web interface.

Where Certificates Are Stored

/etc/letsencrypt/
├── live/example.com/
│   ├── cert.pem        # Your certificate
│   ├── chain.pem       # Intermediate CA chain
│   ├── fullchain.pem   # cert.pem + chain.pem (use this in nginx/Apache)
│   └── privkey.pem     # Private key
├── archive/            # All certificate versions
└── renewal/            # Renewal configuration

Use fullchain.pem (not cert.pem) in your web server config to avoid chain issues.

Automatic Renewal

Certbot installs a systemd timer or cron job that runs certbot renew twice daily. Certificates are renewed when they're within 30 days of expiry.

Verify renewal works

sudo certbot renew --dry-run

Manual renewal

sudo certbot renew

Post-renewal hooks

Reload your web server after renewal:

sudo certbot renew --deploy-hook "systemctl reload nginx"

Or in the renewal config (/etc/letsencrypt/renewal/example.com.conf):

[renewalparams]
post_hook = systemctl reload nginx

Validation Methods Explained

HTTP-01 (most common)

Let's Encrypt requests a file at http://example.com/.well-known/acme-challenge/<token>. Your web server must serve this file on port 80.

Requirements: Port 80 open, web server running Limitations: Doesn't work for wildcard certificates

DNS-01 (required for wildcards)

Let's Encrypt checks for a TXT record at _acme-challenge.example.com.

Requirements: Access to your DNS provider's API (or manual record creation) Advantages: Works for wildcards, doesn't need a running web server

TLS-ALPN-01

Let's Encrypt connects to port 443 and checks a special TLS extension. Less common but useful when port 80 is unavailable.

Wildcard Certificates

Wildcards require DNS-01 validation. You can't use HTTP-01 for *.example.com.

# Interactive (manual DNS)
sudo certbot certonly --manual --preferred-challenges dns \
    -d "*.example.com" -d "example.com"

# Automated with DNS plugin (Cloudflare example)
sudo certbot certonly --dns-cloudflare \
    --dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
    -d "*.example.com" -d "example.com"

DNS plugins exist for most providers: Cloudflare, Route 53, Google Cloud DNS, DigitalOcean, and more.

Common Issues

Port 80 is blocked

Your ISP or firewall blocks port 80. Solutions: - Use DNS-01 validation instead - Use TLS-ALPN-01 on port 443 - Use a DNS plugin for automated DNS validation

Too many certificates

Let's Encrypt limits you to 50 certificates per registered domain per week. If you hit this: - Use a single certificate with multiple SANs instead of separate certs - Use the staging environment for testing (--staging flag) - Wait a week for the rate limit to reset

Certificate doesn't include www

Always include both the bare domain and www:

certbot --nginx -d example.com -d www.example.com

Renewal fails

Common causes: - Web server not running during renewal - Port 80 blocked by firewall - DNS records changed - Server moved to a new IP

Check logs: sudo journalctl -u certbot or /var/log/letsencrypt/letsencrypt.log

"Certificate not trusted" on older devices

Let's Encrypt's root certificate (ISRG Root X1) is trusted by all modern browsers. Very old Android devices (pre-7.1.1) may not trust it. Use fullchain.pem to include the cross-signed chain for maximum compatibility.

Let's Encrypt vs Other Free Options

Provider Validity Wildcard Automation Trust
Let's Encrypt 90 days Yes (DNS-01) ACME Universal
ZeroSSL 90 days Yes ACME Universal
Buypass Go 180 days No ACME Universal
getaCert.com 60 days (free) No Manual / API Requires CA install
Cloudflare 15 years Yes Automatic Cloudflare proxy only

Next Steps


More in Guides