Let's Encrypt in production: the rules that break agencies

30/07/2026 · Laurent TLS and certificates
Let's Encrypt in production: the rules that break agencies

Installing a certificate from Let's Encrypt takes one command and every host has a page about it. Running forty of them across five hosting stacks for clients who occasionally move their DNS without telling you is a different activity, and the things that go wrong there are not in the getting-started guide.

Three of them are worth knowing before you meet them at eleven at night.

The rate limit that stops you is not the famous one

The number everybody quotes is fifty certificates per registered domain every seven days. It is real, and it is generous enough that you will only hit it if you are provisioning subdomains in bulk under a client's single domain, which is a specific and rare situation.

The two that actually stop work are smaller and they trigger precisely when you are trying to fix something.

LimitValueWhen you meet it
Duplicate certificate, same exact set of names5 every 7 days, refilling one every 34 hoursThe fourth time you re-run certbot trying to get a reload to take effect
Failed validations, per identifier, per account5 per hour, refilling one every 12 minutesA broken challenge path plus a retry loop
New orders per account300 every 3 hoursBulk provisioning, rarely otherwise
Certificates per registered domain50 every 7 daysMany subdomains under one client domain

Figures from Let's Encrypt's rate limits documentation, consulted 1 August 2026. Check them before you script anything against them, because they have changed before.

Read the first row again, because it describes a specific and painful evening. Renewal is failing. You run the command. It succeeds, the site still serves the old certificate, and you have not yet worked out that the reload is the problem. You run it again with a different flag. Again. On the fifth attempt you are locked out for thirty-four hours, on a site that is currently broken, and the lockout is per exact set of names so you cannot even work around it by trying the same domain again.

Two habits avoid this entirely. Use --dry-run while you are working out what is wrong: it goes to the staging environment, it does not count, and it tells you whether validation would succeed, which is the question you are actually asking. And separate the three failure points before touching the client at all: did validation pass, did files get written, is the running process serving them. Only the first of those needs Let's Encrypt.

Pick the challenge before you pick the tool

The validation method decides what can break, and most people inherit it from whatever their host's documentation said.

ChallengeNeedsBreaks whenWildcards
HTTP-01Port 80 reachable, /.well-known/acme-challenge/ served as-isA redirect rule, a WAF, a maintenance plugin, a firewall that blocks unknown agentsNo
DNS-01API credentials for the DNS providerToken rotated, permissions tightened, nameservers changedYes
TLS-ALPN-01Port 443, and a server that supports itAnything terminating TLS in front of youNo

For a site you host yourself, HTTP-01 is the right default and its failure mode is a redirect rule somebody added months later. Make sure the challenge path is excluded from every redirect and every access rule, and write that exclusion in the same file as the redirect so the next person sees them together.

For a client whose DNS you manage but whose server you do not, DNS-01 is the only workable option and it comes with a hidden dependency: the credential. An API token for a DNS provider is a secret with an expiry date and an owner, and both of those change. Renewals that ran for two years stop the week somebody tidies up the account permissions.

The wildcard column is the one that forces the decision. If you need *.client.com, you need DNS-01, and there is no argument to have.

The account directory is the thing you must not lose

Certificates are issued to an account, identified by a key pair that was created the first time you ran the client and that you have never thought about since. On a typical Linux host it lives in /etc/letsencrypt, along with the renewal configuration for each certificate, which records which challenge, which credentials, which hooks.

Migrate a server by copying the web root and the database, which is what everybody does, and none of that comes across. The new machine has no account, no renewal config, and no hooks. It serves the certificate you copied, which works, so the migration looks clean. Ninety days later, minus however long the certificate had already run, the site goes dark, and by then the migration is not in anybody's mind as a possible cause.

Put /etc/letsencrypt on the migration checklist next to the database. And after any migration, run a renewal in dry-run mode the same day rather than finding out on a timer you have not verified.

The failure mode that is nobody's fault

Certificate authorities rotate their intermediates, and occasionally a root reaches the end of its life. When that happens, clients that have not been updated in years stop trusting a certificate that has not changed and that no browser complains about.

This is not theoretical: the DST Root CA X3 certificate that Let's Encrypt relied on for cross-signing expired on 30 September 2021, and it took out payment integrations, mobile apps on old Android versions, and a great many curl calls between servers, on sites where nothing had been deployed for months.

You cannot prevent it and you can recognise it. The tell is a browser that is perfectly happy while an automated client refuses, and the split falling along the age of the client rather than along anything you changed. Meanwhile a site can fail for one visitor and work for everyone else for reasons that have nothing to do with the certificate at all, including a clock that is a year out, which is one of the eight distinct faults hiding behind the same red screen in read the second line.

When you cannot run certbot at all

Most client sites are on shared hosting, and the panel issues certificates for you. cPanel's AutoSSL and its equivalents are perfectly good until the day they silently stop, which they do for one reason above all others: the domain's DNS no longer resolves to that server. A client moves their mail, changes nameservers, points the A record at a service they are trialling, and the panel does the correct thing by declining to issue a certificate for a domain it can no longer prove control over. There is no alert, because from the panel's point of view nothing failed.

You will not find this in a log you have access to. You find it by reading the certificate the server is serving, from outside, on a schedule, and noticing that the remaining lifetime stopped climbing back up. Which is the whole argument for treating the served expiry date as the signal rather than the renewal job's exit code, laid out in renewal is three operations.

One practical addition for panel-managed sites: check the certificate for every hostname the client uses, not just the main one. Panels issue per-domain, and a subdomain added after the fact, a mail. host, or a legacy domain still pointing at the site are exactly the entries that get left out and exactly the ones nobody visits until a customer does.

Share this post.
Stay up-to-date

Subscribe to our newsletter

Don't miss this

You might also like