[ OK ]Initializing kernel...
~/im/blog
Hire Me

Let's Talk

Interested in working together or have a question? I'm always open to discussing new projects.

Get in touch

Connect

Find me on social media and professional networks.

Privacy PolicyTerms of Conditions
© 2026 Irfan MiralDeveloped byirfanMiral.com
HomeAbout/ResumeBlogContact
2026-06-24• 5 min read

Automating Let's Encrypt So You Never Think About Certificates Again

Security Let's Encrypt SSL/TLS Automation

Let's Encrypt certificates last 90 days, short enough that manual renewal isn't realistic and automation is effectively mandatory. Most servers I take over do have certbot renew in a cron job or systemd timer already, certbot's installer sets that up by default. What's often missing is the rest of the picture: making sure a renewed certificate actually gets picked up by the service using it, handling domains that need a wildcard certificate, and finding out about a renewal failure before the certificate expires rather than after.

The reload step people forget

Certbot renewing a certificate writes new files to /etc/letsencrypt/live/example.com/. It does not, by itself, tell Nginx, Postfix, or whatever else is using that certificate to start using the new one. The fix is a deploy hook, a script certbot runs after a successful renewal:

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

For a setup where multiple services use certificates, the deploy hook can do more than one thing:

#!/bin/bash
# /etc/letsencrypt/renewal-hooks/deploy/reload-services.sh
systemctl reload nginx
systemctl reload postfix
systemctl reload dovecot

Anything in /etc/letsencrypt/renewal-hooks/deploy/ runs automatically after every successful renewal, which means this is a one-time setup step, not something to remember every 90 days.

Wildcard certificates need DNS-01

The default HTTP-01 challenge (certbot temporarily serves a file that Let's Encrypt checks) doesn't work for wildcard certificates, those require the DNS-01 challenge, which proves domain ownership by creating a TXT record. For providers with a certbot DNS plugin, this is still fully automatable:

certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d example.com -d '*.example.com'

The credentials file holds an API token scoped to DNS edits only, certbot creates the TXT record, waits for it to propagate, and removes it once validation completes, all without manual steps. This is worth setting up even if you don't currently need a wildcard, because the moment a project needs one (a new subdomain for every customer, for example), the alternative is a manual DNS-01 challenge every 90 days, which is exactly the kind of recurring manual task that eventually gets missed.

Finding out about failures before the certificate does

Renewal failing silently is the actual risk, certbot might fail for weeks before a certificate expires, since it retries on every run, and if nothing is watching for that failure, the first sign of a problem is a browser warning on a production site. A simple check, run weekly, catches this early:

#!/bin/bash
# cert-expiry-check.sh
for domain in example.com mail.example.com; do
  expiry=$(echo | openssl s_client -servername "$domain" -connect "$domain:443" 2>/dev/null \
    | openssl x509 -noout -enddate | cut -d= -f2)
  days=$(( ($(date -d "$expiry" +%s) - $(date +%s)) / 86400 ))
  if [ "$days" -lt 14 ]; then
    echo "WARNING: $domain certificate expires in $days days"
  fi
done

A certificate with 14 days left when it should be renewing every 60 days (certbot's default renewal threshold) is a sign that renewal has been silently failing, often due to a changed firewall rule blocking the HTTP-01 challenge, an expired DNS API token for DNS-01, or a domain that's been pointed elsewhere without anyone updating certbot's config.

What "automated" actually means here

A renewal cron job that exists but doesn't reload services, doesn't handle the domains that need DNS-01, and has no way of surfacing a failure isn't really automated, it's a process with a human still implicitly in the loop, just one who doesn't find out there's a problem until a customer does. The actual goal is a setup where a certificate renewing, a service picking up the new certificate, and someone finding out if either step fails, all happen without anyone needing to remember anything on a 90-day cycle. Once that's in place, certificates become one of the few things on a server that genuinely take care of themselves.

PreviousThe First Hour on a New VPS: My Hardening ChecklistNext What I Wish I Knew Before My First MariaDB Galera Cluster