Automation & DevOps

Setting up automatic SSL renewal with Certbot so it never expires again

Let's Encrypt certificates expire every 90 days, and Certbot's auto-renewal is reliable when it's actually configured correctly, which most 'set it and forget it' guides skip past. Here is the setup that actually holds up.

V Vinod Kulkarni
19 August 2026 · 8 min read
Setting up automatic SSL renewal with Certbot so it never expires again

Setting up automatic SSL renewal with Certbot so it never expires again

TL;DR: Certbot installs a scheduled renewal job automatically when you first obtain a certificate, and in the majority of default installations this genuinely works without further action. The failures that cause certificates to expire despite "auto-renewal being on" almost always come from one of four gaps: the renewal timer or cron job silently failing without anyone noticing, the web server not being reloaded after a successful renewal so it keeps serving the old certificate, a firewall or configuration change breaking the HTTP-01 validation Certbot relies on, or Certbot itself becoming outdated and failing against a changed Let's Encrypt API.

Why 90-day certificates make this matter more than it used to

Let's Encrypt issues certificates with a 90-day validity period, deliberately short compared to the one-year-plus periods common with traditional paid certificate authorities. This is a deliberate security design choice (limiting the window of exposure if a private key is ever compromised, and encouraging automation over manual processes prone to being forgotten), but it means a renewal failure that would surface as a once-a-year problem with a traditional certificate instead surfaces up to four times a year with Let's Encrypt, giving four times the opportunity for a silent failure to go unnoticed until the certificate actually expires and visitors start seeing warnings.

This is precisely why "Certbot handles renewal automatically" needs the follow-up question of what happens when that automation itself fails, rather than trusting it blindly, since the failure modes below are common enough in practice that "set and forget" is not quite an accurate description of a genuinely reliable setup.

Confirming auto-renewal is actually installed

When Certbot successfully obtains a certificate, it typically installs either a systemd timer (certbot.timer, on most current systems) or a cron job (on older systems or certain installation methods) that runs the renewal check, by default twice daily, well within the safety margin needed to catch and renew a certificate approaching its 90-day expiry.

Confirm which mechanism is present and active: systemctl status certbot.timer for systemd-based systems, or check /etc/cron.d/certbot for cron-based ones. A missing or inactive timer/cron entry means auto-renewal was never actually set up correctly (uncommon with a standard Certbot installation, but possible if it was manually removed or the installation method skipped it), and this should be the very first thing confirmed before assuming any renewal automation exists at all.

Gap 1: the renewal job runs but nobody notices if it fails

Certbot's renewal check runs silently in the background twice daily by design, which is exactly the behavior you want when everything works and exactly the problem when something goes wrong, since a failed renewal attempt produces no visible symptom until the certificate is genuinely about to expire, at which point Certbot's own internal warning emails (if configured, see below) may be the only signal, easily missed in a busy inbox.

The fix is ensuring Certbot's renewal attempts are actually logged somewhere you would notice a failure, and ideally that failures trigger an active alert rather than a passive log entry you would only check if you already suspected a problem. Certbot writes renewal logs to /var/log/letsencrypt/, and reviewing these periodically, or better, setting up a simple monitoring check that alerts specifically on renewal failure patterns in that log, closes this gap directly rather than relying on remembering to check manually.

Certbot also supports configuring an email address at setup (or via certbot register --update-registration --email you@domain.com after the fact) to receive expiry warnings directly from Let's Encrypt as a backstop, which is worth confirming is set correctly, since a missing or outdated registered email means you lose this safety net entirely without realizing it.

Gap 2: renewal succeeds but the web server never reloads

This is one of the most common real-world causes of an "auto-renewal is definitely on and still somehow expired" report. Certbot successfully obtaining a renewed certificate does not automatically mean your web server (Nginx, Apache) picks up and starts using it; the new certificate file exists on disk, but the running web server process, which loaded the old certificate into memory at its last start or reload, continues serving the old one until it is explicitly told to reload its configuration.

Certbot addresses this through a --deploy-hook (or the older --renew-hook) option, which lets you specify a command to run automatically after a successful renewal, typically something like systemctl reload nginx. If this hook was not configured during initial certificate setup, and it is easy to miss since Certbot's basic setup flow does not always make this step obvious depending on which installation plugin was used, renewals can succeed indefinitely at the DNS/filesystem level while the actual serving certificate silently goes stale and eventually expires from the web server's perspective, even though certbot certificates would show a currently valid, recently-renewed certificate sitting unused on disk.

Check your renewal configuration file (typically in /etc/letsencrypt/renewal/yourdomain.conf) for a renew_hook or equivalent line; its absence is the direct sign this gap applies to your setup.

Flowchart showing the certificate renewal chain and where it commonly breaks: Certbot renewal timer fires, connects to Let's Encrypt, obtains new cert, writes to disk successfully, but web server reload step marked as commonly missing, leaving old cert still in use

Gap 3: HTTP-01 validation breaks after an unrelated change

Certbot's most common validation method (HTTP-01) works by having Let's Encrypt's servers make an HTTP request to a specific, temporary path on your domain to confirm you control it, before issuing or renewing the certificate. This validation step depends on your web server correctly serving that specific path over plain HTTP, unblocked by any firewall, redirect rule, or configuration change.

A later, entirely unrelated change, adding a security plugin or firewall rule that blocks certain paths, adding a blanket HTTP-to-HTTPS redirect that inadvertently also redirects the validation path (which needs to be reachable over HTTP specifically during validation), or a CDN/WAF in front of the origin intercepting the validation request before it reaches Certbot's own web server, can silently break renewal months after the original certificate was successfully issued, with no connection obvious to whoever made that later change.

If renewal starts failing after having worked previously, checking what changed on the server or in front of it (firewall rules, redirect rules, a new CDN configuration) around the time failures started is more productive than assuming Certbot itself is broken, since Certbot's own core mechanism rarely changes unexpectedly on its own.

Gap 4: an outdated Certbot installation

Certbot itself receives updates, and an installation that was set up via a system package manager some time ago and never subsequently updated can, in less common but real cases, fail against changes on Let's Encrypt's side (API changes, deprecated validation methods) that a current Certbot version handles correctly. Checking Certbot's own version (certbot --version) against the current release, and updating via your system's package manager or Certbot's recommended installation method (the snap-based installation is now generally recommended over older OS-package versions specifically because it self-updates), closes this gap without needing ongoing manual attention.

A setup that actually closes all four gaps

Gap Fix
Silent renewal failures Confirm registered email is current; monitor /var/log/letsencrypt/ or set up a log-based alert
Web server not reloaded after renewal Add --deploy-hook "systemctl reload nginx" (or your web server's equivalent) to the renewal config
Validation broken by unrelated changes Whitelist the Let's Encrypt validation path explicitly in any firewall/WAF/redirect rules
Outdated Certbot Use the snap-based Certbot install (self-updating) rather than an old static package version

A final direct verification step worth doing regardless of the above: run certbot renew --dry-run periodically (this simulates the renewal process without actually requesting a new certificate, so it is safe to run anytime) and confirm it completes successfully end to end, including the deploy hook. This single command is the closest thing to a genuine guarantee that your specific setup will actually renew correctly when the real 90-day deadline arrives, rather than assuming based on configuration alone.

FAQs

How do I check when my current certificate actually expires?

Run certbot certificates, which lists every certificate Certbot manages along with its exact expiry date, or use a SSL certificate checker tool pointed at your domain directly, which also confirms what the live web server is actually serving, catching the Gap 2 scenario where the file on disk and the certificate actually in use have diverged.

Does certbot renew --dry-run actually test everything, including the deploy hook?

Yes, a dry run executes the full renewal process including configured hooks, without actually requesting a real certificate from Let's Encrypt, making it a safe and genuinely representative test of whether your complete renewal chain, validation through hook execution, would succeed for real.

I use a CDN in front of my origin server. Does that affect Certbot renewal?

It can, since HTTP-01 validation requires Let's Encrypt's servers to reach a specific path on your actual origin, and a CDN or WAF that intercepts or caches that request instead of passing it through can break validation; many CDNs provide a specific bypass or pass-through rule for the Let's Encrypt validation path, worth confirming is configured explicitly rather than assumed.

Should I switch to DNS-01 validation instead of HTTP-01?

DNS-01 validation (proving domain control via a DNS TXT record rather than an HTTP request) avoids the web-server and firewall-related failure modes described in Gap 3 entirely, and is required anyway for wildcard certificates, but it requires either manual DNS record updates each renewal or API access to your DNS provider for Certbot to automate it, which is a reasonable trade worth considering if HTTP-01 validation has proven fragile in your specific environment.

Can I get an early warning before a renewal actually fails permanently?

Let's Encrypt sends expiry warning emails directly to the address registered with Certbot, typically starting around 20 days before expiry if renewal has not succeeded by then, which is why keeping that registered email current and actually monitored is a meaningful backstop even with everything else configured correctly.

Does every web server need a different reload command in the deploy hook?

Yes, the correct reload command depends on your specific web server and how it is managed (systemctl reload nginx, systemctl reload apache2, or a different command entirely if running under a non-standard setup); using the wrong command in the deploy hook fails silently in the same way an entirely missing hook does, so verify the exact command actually reloads your specific running configuration before relying on it.

Is manual renewal ever necessary if auto-renewal is configured correctly?

No, if all four gaps above are genuinely closed, and a dry run confirms the full chain works end to end, manual renewal should not be necessary; if you find yourself renewing manually on a recurring basis, that recurring need is itself the signal that one of the four gaps described here is still open in your specific setup.

Conclusion

Certbot's automatic renewal is reliable technology, but "reliable" assumes the full chain, the scheduled job actually running, the web server reloading after a successful renewal, validation staying reachable through later unrelated changes, and Certbot itself staying current, is genuinely intact, not just assumed intact because nothing has visibly broken yet. The most common real-world failure, a certificate that renews successfully at the file level while the web server keeps serving the old one, is invisible until the old certificate's actual expiry date arrives.

Running certbot renew --dry-run and confirming the deploy hook fires correctly is the single most direct way to verify your specific setup will hold up, rather than trusting the general reputation of "Certbot handles this automatically" without checking your own configuration against it.

HostCloud automatically issues and renews SSL certificates, including web server reload, as a managed part of every hosting plan, so this entire checklist is handled for you rather than something you need to configure and monitor yourself. See plans at https://hostcloud.in.

Related posts