Guide · Let's Encrypt

Certbot not renewing? Six causes and how to find yours

Checked against sources on 2026-09-29 · 4 min read

When a Let's Encrypt certificate expires, Let's Encrypt is almost never the problem. The renewal ran, or tried to run, and something around it had changed: a server, a firewall rule, a DNS record, a config file. The certificate just kept counting down until someone's browser complained.

This guide goes through six common causes, in the order we would check them. Every command is from the Certbot user guide. If you only have a minute, start with sudo certbot renew --dry-run: it runs a full renewal against the staging server, saves nothing, and prints the real error.

First, is it actually late?

Certbot renews a certificate when less than a third of its lifetime is left. It moved to that rule in version 4.0; before that it used a fixed 30 days. For today's 90-day certificates both rules mean about 30 days before expiry. From 10 February 2027 Let's Encrypt's default certificates last 64 days, so the renewal point moves to about 21 days.

So a 90-day certificate with 40 days left is fine, and one with 20 days left has missed ten days of renewal attempts. Check what the site really serves with our SSL checker, or sudo certbot certificates on the server for what is on disk.

This happens on big sites too. In our scan of the certificates on the 7,847 most-visited sites that answered (the Tranco top 10,000, 28–29 September 2026), 21.4% of certificates came from Let's Encrypt, and 5.1% of those were still being served after the point where a Certbot-style client would have replaced them. Some of those hosts renew late on purpose; from outside we can't tell which. Either way, somebody should look.

1. The renewal job isn't running

Package installs of Certbot add a systemd timer or a cron entry that runs certbot renew twice a day. Rebuild the server, move the site into a container, or install Certbot some other way, and that job may simply not exist any more. Nothing fails, because nothing runs.

  • systemctl list-timers | grep certbot shows the timer and when it last fired.
  • No timer? Look in /etc/crontab and /etc/cron.d/.
  • In a container, the renewal job has to run somewhere that outlives the container.

2. The HTTP challenge can't reach the server

With the HTTP-01 challenge, Let's Encrypt fetches a file from /.well-known/acme-challenge/ on port 80 (challenge types). A site that worked last year can break this without anyone noticing:

  • the webroot moved, so Certbot writes the file where the web server no longer looks;
  • a new redirect rule or security plugin answers that path with a 301 to a login page or a 403;
  • a firewall or cloud security group now blocks port 80;
  • a CDN in front of the site answers the path itself.

The dry run shows the URL Let's Encrypt tried and what it got back. Request that same URL yourself from outside the server and compare.

3. DNS changed

If the domain now points at another server or a CDN, the challenge goes there and fails. With the DNS-01 challenge the failure is quieter: the plugin's API token belongs to the old DNS host, or it expired, so Certbot can't create the TXT record. Moving DNS is a common reason for a setup that ran for years and then stopped.

4. A CAA record leaves Let's Encrypt out

CAA records list the CAs allowed to issue for a domain (Let's Encrypt on CAA). If someone added CAA for another CA, for example while buying a certificate elsewhere, Let's Encrypt must refuse. The error in the dry run says CAA plainly. Check with dig CAA example.com and add letsencrypt.org if Let's Encrypt should still issue.

5. Rate limits after repeated failures

A broken renewal that retries in a loop can run into Let's Encrypt's rate limits, including one for failed validations. Then the fix works and the renewal is still refused for a while. Read the current limits on that page rather than from memory, test fixes with --dry-run (staging has its own, higher limits), and renew for real once.

6. It renewed, but the site serves the old certificate

This one fools people because Certbot reports success. The new certificate is on disk; nginx or Apache still has the old one in memory until it reloads. Compare the expiry date certbot certificates shows with the one our checker shows from outside. If the file on disk is newer, add a deploy hook, for example --deploy-hook "systemctl reload nginx". Certbot runs it once for each certificate it renews.

How to hear about it next time

Let's Encrypt stopped sending expiry emails in June 2025, so nobody tells you when a renewal stops. The only reliable signal comes from outside: something that connects to each hostname the way a browser does, reads the certificate it gets, and knows when that certificate should already have been replaced.

  • For a handful of sites, the bulk SSL checker shows every certificate's expiry date and issuer in one table, once a week.
  • For client sites, ExpiryOwl checks every certificate every 6 hours and flags a Let's Encrypt certificate that is still being served after the point where it normally renews, usually weeks before it expires. The free plan covers 5 domains.
  • Whatever you use, send the alert to an address somebody reads, not the ACME account email of a developer who left.

Agencies meet all six causes at once, because client sites move hosts, DNS and CDNs without telling anyone. Our page for web design agencies covers how we group those sites by client.

How we measured

We took the Tranco list (ID 64X3X, generated 27 September 2026), tried www. and then the bare domain for each of the top 10,000 entries, and made one TLS connection on port 443 per name with our own checker: no web page was requested. "Past the usual renewal point" means a Let's Encrypt certificate that has fewer days left than a third of its lifetime minus three days (27 days for a 90-day certificate), the same line our monitor uses. We publish only totals and never name a site.

Sources

  1. Certbot user guide
  2. Certbot changelog (4.0: renew at a third of the lifetime)
  3. Let's Encrypt: Challenge types
  4. Let's Encrypt: Certificate Authority Authorization (CAA)
  5. Let's Encrypt: Rate limits
  6. Let's Encrypt: Decreasing certificate lifetimes to 45 days
  7. Tranco top-sites list

FAQ

Questions

How do I test Certbot renewal without renewing?

Run sudo certbot renew --dry-run. It performs a full renewal against Let's Encrypt's staging server, saves nothing, and prints the error that a real renewal would hit.

When does Certbot renew a certificate?

Since version 4.0, when less than a third of the certificate's lifetime is left: about 30 days before expiry for a 90-day certificate, about 21 days for a 64-day one.

Certbot says the renewal succeeded but the browser shows the old date. Why?

The web server hasn't reloaded, so it still serves the old certificate from memory. Reload it, and add a deploy hook so Certbot reloads it after every renewal.

Start with five domains, free.

The free plan watches 5 domains for one client: certificates, domain registration, DNS and uptime every 15 minutes. No card, no trial clock.