Getting Certbot Installed Without Losing Your Mind
I always install via package manager first: apt install certbot python3-certbot-nginx
on Ubuntu or yum install certbot python3-certbot-apache
on CentOS. Don't use pip installation unless you enjoy dependency hell - learned that one the hard way debugging Python conflicts at 2am. Official Docker images work great but for fuck's sake mount /etc/letsencrypt
properly or you'll lose certs on container restart like I did.
The Snap package is reliable but puts everything in weird paths. Newer Certbot versions drop support for older Python versions regularly - they ditched Python 3.8 recently and it's only going to get worse. Pulls in a bunch of Python dependencies so it's hefty compared to shell-based alternatives, but the plugin ecosystem makes it worth the bloat.

Challenge Methods: Pick Your Poison

HTTP-01 challenges work by serving a file at /.well-known/acme-challenge/
. Port 80 must be open to the internet or it fails. No wildcard certs with this method. Most common for simple deployments.
DNS-01 challenges add TXT records to your DNS. Works behind firewalls, enables wildcards, but requires API access to your DNS provider. If your DNS provider doesn't have a supported plugin, you're stuck doing this manually. Painful but sometimes necessary.
TLS-ALPN-01 uses port 443 when port 80 is blocked. Useful for corporate networks but not all clients support it. Stick with HTTP-01 unless you have a damn good reason not to.
Plugin Reality Check
The Apache and Nginx plugins modify your configs automatically, and sometimes they break shit - but honestly they usually work. I always test with `--dry-run` first because I've seen the Apache plugin generate configs so broken that Apache wouldn't even start.
Webroot mode is what I use when I don't trust the plugins - Certbot writes files to your web directory, you handle the server config yourself. More work but way fewer surprises. Standalone mode runs its own temporary server which is great for testing but will stop your real server.
DNS plugins exist for major providers (Route 53, Cloudflare, Google DNS). Each needs its own package and credentials file. Store those API keys securely because I've seen someone accidentally commit theirs to GitHub and get a fun surprise bill.
Renewal: Set It and (Mostly) Forget It
The default cron job runs certbot renew
twice daily, which sounds excessive but it only actually renews certs within 30 days of expiration. When things break, I always check /var/log/letsencrypt/letsencrypt.log
first - saves a lot of debugging time.
Latest Certbot versions have ACME Renewal Info (ARI) support for smarter renewal timing. Certificate authorities can now suggest optimal renewal windows, which is a nice feature but doesn't fix broken configs or misconfigured firewalls - trust me on that one.
Production Lessons I Learned the Hard Way
I always use `--dry-run` before running renewal in production because I hit rate limits early in my Let's Encrypt journey and debugging when everything's on fire sucks ass. Keep backups of your old certificates - I once lost all certificates because I forgot to mount the Docker volume and spent a Sunday morning re-issuing everything.
I monitor certificate expiration dates obsessively now. Set alerts for 30, 7, and 1 day before expiry because automation fails when you least expect it. Found out the hard way when my personal blog went red in browsers for 3 days before I noticed. SSL Labs Server Test is bookmarked for a reason.
File permissions bit me once: /etc/letsencrypt/live/*/privkey.pem
should be 600. Certbot handles this correctly, but I wrote a custom backup script that changed permissions and broke everything. Test your renewal process monthly, not when certificates are about to expire. I block out 2 hours/month for maintenance because something always breaks.