Lapsentry

Why Let's Encrypt renewals fail

Updated Oct 2026 · 5 min read

The five causes we see most often, and how to catch them early.

Let's Encrypt certificates last 90 days and the usual clients (Certbot, acme.sh, Caddy, Traefik, cert-manager) renew them automatically about 30 days before expiry. When renewal breaks, nothing warns you until browsers show a full-page error: Let's Encrypt stopped sending expiry reminder emails in 2025, and certificate lifetimes keep getting shorter, so renewals happen more often and have more chances to fail.

A useful rule of thumb follows: an ACME certificate with less than 30 days left is already a renewal that failed at least once. These are the causes we see most often, with the command that confirms each one.

1. The validation file is not reachable

HTTP validation asks the domain to serve a token under /.well-known/acme-challenge/ on port 80. A redirect to another host, a firewall that closed port 80, a CDN or WAF rule, geo-blocking, basic authentication or a maintenance page in front of the site makes every renewal fail.

curl -i http://harborgoods.com/.well-known/acme-challenge/test

A 404 from your own web server is the expected answer. A redirect to another domain, a 403, a timeout or a login page means the certificate authority gets the same thing. Redirecting to HTTPS on the same host is fine.

2. DNS moved, the certificate did not

After a migration, the domain points to a new server, a CDN or a load balancer while the renewal job still runs on the old machine. The old server can no longer prove it controls the domain, and the new one may be serving a certificate nobody renews.

dig +short A harborgoods.com
dig +short AAAA harborgoods.com

An AAAA record pointing to an address that no longer answers is a frequent trap: Let's Encrypt prefers IPv6 when both exist. With DNS validation instead, check that the API token used by the client to create the TXT record has not expired or lost its permissions.

3. A CAA record forbids the issuer

A CAA record lists the certificate authorities allowed to issue for the domain. Switch providers, or let a CDN issue certificates for you, without updating it and issuance is refused.

dig +short CAA harborgoods.com

No answer means every authority is allowed. If records exist, one of them must contain letsencrypt.org for Let's Encrypt to issue. CAA records are inherited from parent domains, so check the apex when a subdomain fails.

4. The renewal ran, but nothing reloaded

The certificate was renewed on disk, but the web server kept the old one in memory because nobody reloaded it. The same happens when the certificate is copied to a load balancer, a CDN or a mail server by a script that stopped working.

openssl s_client -connect harborgoods.com:443 -servername harborgoods.com </dev/null 2>/dev/null \
  | openssl x509 -noout -issuer -dates

Compare the notAfter date with the file on disk. Certbot runs deploy hooks for this: --deploy-hook "systemctl reload nginx" reloads the server after every successful renewal.

5. The renewal job stopped

The cron job or systemd timer was removed during an upgrade, the server was rebuilt from an image without it, or the container that ran it no longer exists.

systemctl list-timers | grep -i certbot
sudo certbot renew --dry-run

The dry run goes through the whole validation against the staging environment without touching your certificates: if it fails, the next real renewal will too, with the same error message.

And rate limits

Repeated failed attempts, a script that requests a new certificate at every deploy, or many subdomains issued one by one hit Let's Encrypt rate limits: failed validations are limited per hostname and per hour, and new certificates per registered domain and per week. Once limited, you wait. Fix the cause with --dry-run first, and group related subdomains in one certificate.

Shorter lifetimes ahead

Browsers and certificate authorities have agreed to shorten the maximum lifetime of public certificates in steps: 200 days from March 2026, 100 days from March 2027 and 47 days from March 2029. Let's Encrypt, already at 90 days, has announced shorter certificates as well. Manual renewals will not survive this schedule, and every automated renewal will run several times more often than today.

In practice, this means every weakness listed above shows up sooner. A validation path that breaks once a year today may break every month tomorrow. Treat certificate renewal like a backup: automate it, test it with a dry run after every infrastructure change, and monitor the result from outside rather than trusting the job's own logs.

Catch it before visitors do

  1. 1Keep certificate alerts at D-14 and D-7: with a 30-day renewal window, an alert at D-14 means renewal has failed for two weeks.
  2. 2Watch for certificates whose issuer changes unexpectedly: it often reveals a CDN or a host that took over.
  3. 3After fixing, run the renewal by hand and check the served certificate with the openssl command above.
  4. 4Write down where each certificate is renewed and deployed, so the next migration moves the renewal job along with the site.
  5. 5Keep the same watch on the domain itself: a certificate cannot be renewed once the name has lapsed (see what happens when a domain expires).
Alerts at D-14 and D-7 on certificates give you two weeks to fix any of these before visitors see an error.
Building an integration?REST API, webhooks and MCP server are documented separately.Open the docs