If you hold certificates for a few hundred customer domains, the number of renewals you run each year is on its way to multiplying twice. The schedule for that is already published and the first step of it has already happened. An estate that renews by hand, or by a cron job nobody has read in two years, will start failing in public, one customer at a time.
The schedule that already started
Ballot SC-081v3 passed at the CA/Browser Forum in April 2025 and wrote a set of dates into the TLS Baseline Requirements. From 15 March 2026 the maximum validity period of a subscriber certificate is 200 days. From 15 March 2027 it drops to 100 days. From 15 March 2029 it drops to 47.
The domain validation data reuse period falls on the same dates, to 200 days, then 100, and then 10. That second number is the one operators miss. Once validation data may only be reused for 10 days, a renewal stops being a signature request and becomes a fresh proof of control over every name on the certificate, every single time. Any part of your process that depends on a human doing something has to go.
Why DNS-01, and why you must not hold the customer's DNS credentials
HTTP-01 needs port 80 reachable on the exact name being validated, and it cannot issue wildcards. Let's Encrypt documents both limits plainly, "The HTTP-01 challenge can only be done on port 80" and "This challenge cannot be used to issue wildcard certificates." Across a hosting or agency estate that means every customer must have already pointed DNS at you and kept port 80 open before a renewal can succeed, which is precisely the condition that fails at three in the morning during a migration you were not told about.
DNS-01 works no matter where the traffic goes, but at first glance it demands something worse. You have to write a TXT record in the customer's zone. Collecting DNS API credentials from a few hundred customers is a liability you do not want to carry and an onboarding step most of them will never finish.
The way out is documented by Let's Encrypt itself. "you can use CNAME records or NS records to delegate answering the challenge to other DNS zones. This can be used to delegate the _acme-challenge subdomain to a validation-specific server or zone."
The customer creates one CNAME record, once, and never touches DNS again. You hold credentials only for your own zone, and you can never accidentally change a customer's MX record.
The delegation record and a client that speaks it
acme.sh implements this as alias mode. With --challenge-alias the CNAME carries the _acme-challenge. prefix on both sides.
_acme-challenge.customer.com. IN CNAME _acme-challenge.acme.yourcompany.com.
The issuance then runs with credentials for acme.yourcompany.com only, and the DNS provider token goes in the environment ahead of the command.
export CF_Token="your-cloudflare-api-token"
acme.sh --issue -d customer.com -d www.customer.com \
--challenge-alias acme.yourcompany.com \
--dns dns_cf
The other form, --domain-alias, points the CNAME at a name without the underscore prefix, which helps when a customer's DNS interface refuses to create records that start with an underscore.
_acme-challenge.customer.com. IN CNAME customer-com.acme.yourcompany.com.
acme.sh --issue -d customer.com \
--domain-alias customer-com.acme.yourcompany.com \
--dns dns_cf
One more thing to check on install. acme.sh supports several certificate authorities through --server, with short names including letsencrypt, zerossl, buypass and google, and the default is not Let's Encrypt. Set it deliberately rather than discovering it later.
The rate limits that bite at this size
Let's Encrypt publishes its limits, and which one hurts you depends entirely on how your names are shaped.
If every certificate covers a different customer-owned domain, the limit you meet first is orders. "Up to 300 new orders can be created by a single account every 3 hours. The ability to create new orders refills at a rate of 1 order every 36 seconds." A first-time bulk issuance across several hundred names has to be paced, and a client that retries a failing batch in a tight loop will spend the entire budget on the same broken domain.
If instead you issue names under your own domain, one per customer, all of them share a registered domain and you meet a far smaller number. "Up to 50 certificates can be issued per registered domain (or IPv4 address, or IPv6 /64 range) every 7 days." Let's Encrypt identifies the registered domain using the Public Suffix List, so a platform handing out customer.yourplatform.com names stops at 50 a week. There are two ways out, spreading customer names across several registered domains you own, or putting more names onto fewer certificates.
The failure limit is what turns a small mistake into an outage. "Up to 5 authorization failures per identifier can be incurred by one account every hour". A customer who deletes their delegation CNAME will burn that in minutes if your renewal job retries aggressively, and every working domain queued behind it waits. Rate limit your own retries, and treat a validation failure as a support ticket rather than something to hammer at.
Run bulk work against the staging environment first, which carries significantly higher limits and issues certificates no browser trusts.
Renew on the certificate authority's schedule, not your own
The old advice was to renew at some fixed fraction of the lifetime. That does not survive a lifetime that changes three times in four years, and it is also why mass renewal events pile up on the same hour of the same day.
ACME Renewal Information, published as RFC 9773, lets the certificate authority tell the client when to renew. Let's Encrypt attaches a second and blunter benefit to it. "Renewals coordinated by ARI offer the unique benefit of being exempt from all rate limits." For an operator holding hundreds of domains that turns the whole rate limit conversation into a non-event, and it also lets the CA pull your renewal forward when a certificate has to be revoked early.
acme.sh writes a daily cron entry when it installs, and its documentation states that certificates "will be renewed automatically every 30 days, or earlier when the CA's ARI says so". Confirm the entry exists rather than assuming it.
crontab -l | grep acme.sh
acme.sh --info -d customer.com
What to monitor, because the customer will not tell you
Two checks catch nearly everything. Watch the delegation, because a customer switching DNS provider silently drops the CNAME and nothing fails until the next renewal.
dig +short CNAME _acme-challenge.customer.com
Then watch the expiry from outside your own automation, so that a broken renewal job cannot also be the thing reporting success.
echo | openssl s_client -servername customer.com -connect customer.com:443 2>/dev/null \
| openssl x509 -noout -enddate -subject
Alert on days remaining rather than on job failures. A renewal job that has quietly stopped running produces no failures at all, which is why it is the one that catches people.
Certificate lifecycle across an estate this size is part of servers management, and the architecture work of getting delegation and issuance right the first time sits in infrastructure setup. For the single-server version, with certbot and one web server, see our guide to automated certificate management.
Talk to the engineer who will own your stack.
No account managers, no offshore handoff. Senior DevOps, direct. Tell us what you are dealing with and you get a straight answer.
Related Articles
How to Detect and Respond to a Compromised Linux Server
A practical incident response guide for Linux servers: identifying signs of compromise, initial triage, evidence preservation, containment, rootkit detection, and writing an incident report.
SecurityEleven npm Packages Compromised in a 53 Minute Attack That Steals Every Credential Your Build Host Can Reach
On August 4, 2026 a worm pushed malicious versions of eleven npm caching packages inside a 53 minute window, harvesting npm tokens, GitHub PATs, AWS credentials, Kubernetes service account tokens and SSH keys. The headline was keyv and its 604 million monthly downloads, but keyv was the safest package on the list: its malicious release was a major version bump that no caret range accepts. The other ten were patch bumps, silently eligible for every dependency range in the ecosystem. That distinction, not the download count, decided who got hit. This is a practical guide to the defenses that actually change the outcome: what your semver range really grants, why npm install and npm ci are not interchangeable, when to disable install scripts and what breaks when you do, and how to check a tree you already have.
SecurityAWS WAF Configuration for Web Application Security
Deploy and configure AWS WAF with managed rule groups, custom rules, rate limiting, and bot control to protect web applications from common threats.