Scheduling TLS certificate renewal
Certbot and acme.sh already schedule themselves. Here's what's left for you to own.
The problem
If you're using certbot, it already installed a systemd timer (certbot.timer) or a cron entry in /etc/cron.d/certbot during package install, running twice daily and renewing certificates only when they're within 30 days of expiry. acme.sh does the same via its own cron entry created during `--install-cron`. Adding a second, independent renewal cron job is the common mistake: two renewal processes can race for the same domain's HTTP-01 challenge or ACME account lock, and one fails.
The gap most teams have is the reload step. A cert renews fine, but nginx or haproxy never reloads to pick up the new file, so the service keeps serving the old certificate until someone restarts it, or until it expires anyway.
Check for an existing certbot/acme.sh timer before adding one.
Run `systemctl list-timers | grep certbot` or `crontab -l` for the acme.sh user first. If one exists, don't add a second. Make sure its `--deploy-hook` (certbot) or `--reloadcmd` (acme.sh) actually reloads the service that terminates TLS. That reload is usually the missing piece.
Recommended schedule
0 3,15 * * *
Twice daily is certbot's own default cadence. That is frequent enough that a transient failure (rate limit, DNS hiccup) gets retried well before the 30-day renewal window closes. Only needed if you're not using the packaged certbot cron/timer at all, e.g. a custom ACME client.
Check any expression at the cron parser, or browse more at the cron guide.
Example crontab entry
# norc: cert-renew Certbot renewal with nginx reload
0 3,15 * * * /usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx" >> /var/log/certbot-renew.log 2>&1 Failure modes to watch for
- Duplicate renewal jobs (packaged cron/timer plus a hand-added one) racing for the same ACME account lock, causing one to fail with a lock-file error.
- Renewal succeeds but no deploy-hook/reloadcmd reloads the terminating service, so the new cert sits on disk unused until expiry takes down the old one.
- HTTP-01 challenge fails silently behind a load balancer or CDN that doesn't route /.well-known/acme-challenge/ to the renewing host.
- Renewal email notifications going to an inbox nobody reads, so a renewal that's been failing for weeks is only discovered when the site goes down.
How norc helps
norc puts every renewal job on the box in one view with its run history, so a certbot cron failure or a missed run shows up next to your other jobs instead of in a renewal email nobody reads. You can edit the line, deploy hook included, from wherever you are, without SSH.