← Course Index

SSL Termination with Let's Encrypt

~20 min · Nginx · Nginx Cheat Sheet →

Ref
Primary Source
DigitalOcean — How to Secure Nginx with Let's Encrypt on Ubuntu

Step-by-step Certbot + Nginx setup. Follow this on your server after reading the lesson. DigitalOcean →

Certbot: The Standard Way

Certbot is the official ACME client for Let's Encrypt. It requests a certificate, validates your domain ownership, and automatically edits your Nginx config to add SSL.

# 1. Install Certbot (Ubuntu)
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

# 2. Your Nginx must already have a server block for your domain
# and port 80 must be open in your firewall

# 3. Get certificate + auto-configure Nginx
sudo certbot --nginx -d yourapp.com -d www.yourapp.com

# Certbot will:
# - Prove domain ownership via HTTP challenge
# - Issue certificate from Let's Encrypt
# - Modify your Nginx config to add ssl_certificate lines
# - Set up HTTP→HTTPS redirect
# - Schedule automatic renewal

# 4. Test renewal (won't actually renew)
sudo certbot renew --dry-run

# 5. List your certificates
sudo certbot certificates
💡 DNS must point to your server FIRST

Certbot validates domain ownership by making an HTTP request to your domain. Your A record must point to the server you're running Certbot on, or the challenge will fail. Let's Encrypt also supports a DNS challenge for wildcard certs.

Wildcard Certificates

For *.yourapp.com (covering api, cdn, admin, etc.), use the DNS challenge:

# Get wildcard cert via DNS challenge
sudo certbot certonly \
  --manual \
  --preferred-challenges dns \
  -d yourapp.com \
  -d "*.yourapp.com"

# Certbot will ask you to add a TXT record to your DNS:
# _acme-challenge.yourapp.com → "some-token-value"
# Add it in Cloudflare/Route53, wait 30-60s for propagation, then press Enter

Auto-Renewal

Certbot installs a systemd timer (or cron job) that runs twice daily and renews certs expiring within 30 days. Check it:

# Check the renewal timer
sudo systemctl status certbot.timer

# Manually trigger renewal (without --dry-run)
sudo certbot renew

# Certbot also runs a post-renewal hook to reload Nginx
# Usually auto-configured at: /etc/letsencrypt/renewal-hooks/deploy/

What Certbot Adds to Your Nginx Config

# After running certbot --nginx, your config gains:
ssl_certificate     /etc/letsencrypt/live/yourapp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourapp.com/privkey.pem;
include             /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam         /etc/letsencrypt/ssl-dhparams.pem;

# And an HTTP redirect block:
server {
    listen 80;
    server_name yourapp.com www.yourapp.com;
    return 301 https://$host$request_uri;
}
⚠️ Don't edit Certbot's managed sections

Certbot marks sections of your Nginx config with comments. Editing between these markers may break renewal. Put your custom SSL settings outside the managed sections.

Using AWS Certificate Manager (ACM) Instead

If you're using AWS CloudFront or an ALB, use ACM for free certificates — no Certbot needed. ACM handles renewal automatically.

# Via AWS CLI — request a certificate
aws acm request-certificate \
  --domain-name yourapp.com \
  --subject-alternative-names "*.yourapp.com" \
  --validation-method DNS \
  --region us-east-1

# ACM gives you CNAME records to add to DNS for validation
# Once validated, use the certificate ARN in CloudFront/ALB

Check Your Understanding

1. You run `certbot --nginx -d yourapp.com` but get "Could not connect to server" error. Most likely cause?
2. You need a certificate for api.yourapp.com, cdn.yourapp.com, and admin.yourapp.com. What's the most efficient approach?
3. Using AWS CloudFront with HTTPS. Which certificate tool should you use?