One cert for all your subdomains. Setup takes 15 minutes and renewal is automatic. Here is exactly how to do it.
If you run multiple subdomains off a single domain (docs.yourdomain.com, api.yourdomain.com, media.yourdomain.com etc), managing individual Let's Encrypt certs for each one gets tedious fast. A wildcard cert covers *.yourdomain.com with a single certificate and a single renewal process.
The catch is that wildcard certs require DNS validation rather than HTTP validation. You cannot prove domain ownership by placing a file on a web server because a wildcard cert covers subdomains that might not even have a web server. Instead, you create a TXT record in your DNS to prove you control the domain.
With Cloudflare DNS, this can be fully automated using the certbot-dns-cloudflare plugin.
Setup
Install certbot and the plugin:
sudo apt install certbot
pip install certbot-dns-cloudflare --break-system-packagesCreate a Cloudflare API token. Go to Cloudflare dashboard > Profile > API Tokens > Create Token. Use the "Edit zone DNS" template and scope it to your specific zone. Save the token.
Create the credentials file:
mkdir -p ~/.secrets
cat > ~/.secrets/cloudflare.ini << EOF
dns_cloudflare_api_token = your_api_token_here
EOF
chmod 600 ~/.secrets/cloudflare.iniThe chmod 600 is important. Certbot will refuse to use the credentials file if it is world-readable.
Getting the cert
certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
-d yourdomain.com \
-d *.yourdomain.com \
--agree-tos \
--email [email protected]The process takes about 30-60 seconds. Certbot creates a TXT record in your DNS automatically, waits for it to propagate, validates it, gets the cert, then cleans up the TXT record.
Certs are saved to /etc/letsencrypt/live/yourdomain.com/.
nginx config
Point your nginx SSL directives at the wildcard cert:
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;You can use the same cert block in every server block that handles subdomains. nginx handles it correctly.
Auto-renewal
Certbot installs a systemd timer or cron job automatically. Check that it is set up:
systemctl status certbot.timer
# or
crontab -l | grep certbotIf you want to also reload nginx after renewal (to pick up the new cert), add a deploy hook:
cat > /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh << EOF
#!/bin/bash
nginx -s reload
EOF
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.shThis runs automatically after every successful renewal. The cert renews 30 days before expiry, so you should never see an expired cert in production.