To renew an SSL certificate, you prove again that you control the domain, get a new certificate from the certificate authority, and install it with the web server reloaded, before the old one's notAfter date. With Let's Encrypt, Caddy, cPanel AutoSSL, Cloudflare or a cloud load balancer that happens automatically; your job is to confirm the automation still works and to monitor the expiry date from outside. This guide covers why certificates keep getting shorter, how each renewal stack works, the ways renewal quietly stops, and how to hear about it weeks before visitors do. The wider picture of what the SSL panel grades is in SSL/TLS checks that matter.
Quick answer
- The maximum lifetime of a public certificate is 200 days since 15 March 2026, 100 days from 15 March 2027 and 47 days from 15 March 2029. Manual renewal no longer scales.
- Use a stack that renews on its own: certbot's timer, acme.sh, Caddy, cPanel AutoSSL, Cloudflare edge certificates or a managed load-balancer certificate.
- Prove the automation is alive:
sudo certbot renew --dry-run, the timer status, and a reload hook so the server serves the new file. - Monitor the expiry date from outside. The SSL checker warns under 30 days and fails under 7; an uptime monitor with a certificate check e-mails you.
- One command shows the dates:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates.
Why SSL certificate expiration matters
The moment the notAfter date passes, every browser shows a full-page warning instead of your site: "Your connection is not private", NET::ERR_CERT_DATE_INVALID in Chrome, SEC_ERROR_EXPIRED_CERTIFICATE in Firefox. Most visitors leave, and on a site that sends HSTS there is no "proceed anyway" link at all. What visitors see and how to read each error is in Your connection is not private.
The invisible half fails harder. API clients, payment webhooks and mobile apps stop with a certificate error and no button to press. A mail server sharing the certificate makes every staff phone warn. Googlebot cannot fetch the page; a day is survivable, a week starts to cost rankings.
Why certificates expire sooner every year
A certificate says that, at the time of issue, you controlled the domain. The longer it lasts, the longer a stolen key or a domain that changed hands stays trusted, and revocation never worked well in browsers. So the industry chose short lifetimes.
In April 2025 the CA/Browser Forum, whose rules every public CA follows, passed ballot SC-081v3. It cuts the maximum lifetime to 200 days for certificates issued from 15 March 2026, 100 days from 15 March 2027 and 47 days from 15 March 2029, and shrinks how long a domain validation can be reused to 10 days by 2029. Let's Encrypt, which issues 90-day certificates, announced in December 2025 that its default will drop to 64 days on 10 February 2027 and 45 days on 16 February 2028, with an opt-in 45-day profile available since May 2026.
Two more changes matter for monitoring. Let's Encrypt stopped sending expiry reminder e-mails in June 2025, so "they will warn me" no longer holds. And ACME Renewal Information (ARI, RFC 9773) lets a CA tell clients when to renew, including early after a mass revocation; certbot supports it from version 4.1.
How getReport checks it
The checker opens a TLS connection with the hostname as SNI, as a browser does, reads the certificate and validates the chain against the public root store. Three findings come from that handshake:
The evidence line shows the date: Certificate valid until 2026-12-31 (97 days from now). It warns under 30 days and fails under 7, so a certificate that renewed on schedule passes and one whose renewal was missed warns with time to spare.
The chain fails when the certificate has expired, the server sends it without its intermediate, or it does not cover the hostname. The evidence names the error, such as UNABLE_TO_GET_ISSUER_CERT_LOCALLY for a missing intermediate.

The report is a snapshot: right for "is renewal working?" after a change, not a replacement for a monitor that runs every day.
How to renew an SSL certificate, stack by stack
1. Find out which stack renews it
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -issuer -dates- Issuer
Let's EncryptorZeroSSL, 90-day validity: an ACME client on your server (certbot, acme.sh, lego), Caddy, or cPanel AutoSSL. - Issuer
Google Trust Services,Let's EncryptorCloudflareon a proxied site: Cloudflare's edge certificate. Your origin has a separate one (step 5). - Issuer
Amazonor another cloud: a managed load-balancer certificate. - A commercial issuer with a long validity: probably installed by hand. Plan to automate it; from March 2027 it will need doing at least every 100 days.
2. certbot: check the timer, not the certificate
certbot installs a systemd timer that runs twice a day. Since certbot 4.0 it renews when less than a third of the lifetime remains (about 30 days on a 90-day certificate), or earlier when the CA's ARI says so.
systemctl list-timers | grep -i certbot # apt: certbot.timer; snap: snap.certbot.renew.timer
sudo certbot renew --dry-run # full renewal against the staging CA, nothing changes
sudo grep -i "renew" /var/log/letsencrypt/letsencrypt.log | tail -5A dry run proves the challenge still works: port 80 reachable for HTTP-01, or the DNS plugin's credentials valid for DNS-01. The timer does not tell the web server to load the new file unless certbot's nginx or Apache plugin installed it. For webroot or standalone setups, add a deploy hook once in /etc/letsencrypt/cli.ini:
deploy-hook = systemctl reload nginxWithout it, the file on disk is fresh and the one being served is old, the most confusing version of this outage.
3. acme.sh, Caddy, cPanel and load balancers
acme.sh installs a daily cron job (crontab -l | grep acme.sh) and needs --reloadcmd so the server picks up new files. Caddy obtains and renews certificates itself and reloads without a restart; it needs ports 80 and 443 reachable, or a DNS module. Failures are in journalctl -u caddy | grep -i renew. cPanel AutoSSL runs on the host's schedule; it fails when a subdomain no longer points at the server or an .htaccess rule catches /.well-known/acme-challenge/, and its log names the domain. Load balancers (AWS ACM, Google-managed, Azure App Service) renew as long as the DNS validation record stays in place; delete it during a clean-up and renewal stops.
4. Renewing a paid certificate by hand
If you must renew manually: generate a new key and CSR on the server, order the renewal from your CA, pass domain validation (DNS record, file or e-mail), then install the new certificate with its intermediate bundle and reload.
openssl req -new -newkey rsa:2048 -nodes -keyout example.com.key -out example.com.csr -subj "/CN=example.com"A new key at each renewal is good practice. Put a calendar reminder 30 days before expiry, and move to ACME as soon as you can; most commercial CAs now offer ACME endpoints too.
5. Behind Cloudflare: two certificates, two clocks
Visitors see Cloudflare's edge certificate, which Cloudflare renews. Between Cloudflare and your server is a second certificate on the origin. In "Full (strict)" mode, when it expires, visitors get Cloudflare's error 526 even though the edge certificate is fine; see Cloudflare errors 525 and 526. A Cloudflare Origin CA certificate lasts up to 15 years and is trusted only by Cloudflare; a normal ACME certificate on the origin needs DNS-01, because HTTP-01 passes through Cloudflare.
6. Cover every name and install the full chain
example.com and www.example.com must both be on the certificate; a missing name fails with a hostname mismatch although nothing expired. Check with openssl x509 -noout -ext subjectAltName in the same pipe as above. Certificate transparency logs (crt.sh) list every certificate issued for your domain, which is how you find a forgotten subdomain with its own clock.
Serve the leaf with its intermediate: fullchain.pem, not cert.pem. Desktop browsers often paper over a missing intermediate; Android, curl and API clients do not. openssl s_client -connect example.com:443 -servername example.com </dev/null 2>&1 | grep "Verify return code" should print 0 (ok). Details are in certificate chain errors and intermediate certificates.
SSL certificate monitoring from outside
Automation fails silently; monitoring makes it loud.
- An uptime monitor with a certificate check. Set the alert at 14 days: long enough to fix a broken renewal, short enough that a normal renewal never triggers it.
- A cron job on another machine that mails you under 14 days:
#!/bin/bash
# /usr/local/bin/cert-days.sh example.com
host="$1"
end=$(echo | openssl s_client -connect "$host:443" -servername "$host" 2>/dev/null \
| openssl x509 -noout -enddate | cut -d= -f2)
days=$(( ( $(date -d "$end" +%s) - $(date +%s) ) / 86400 ))
[ "$days" -lt 14 ] && echo "$host certificate expires in $days days ($end)" | mail -s "Certificate warning: $host" you@example.com- The report, monthly, on each hostname. It also catches what monitors skip: the chain, the protocol version, HSTS.
Monitor every hostname with a padlock: www, the API, mail and staging hosts each have their own certificate and clock.
Common failure modes
Watch out
Each of these leaves a certificate that is valid today and gone on a date nobody is watching. Check for all five after any server, DNS or firewall change.
- The renewal job stopped. The server was rebuilt and the timer not re-enabled, or the cron job lived in a deleted user's crontab.
- Port 80 was blocked "for security". HTTP-01 needs
http://example.com/.well-known/acme-challenge/. Keep port 80 open and redirecting, and exempt the challenge path. - The DNS credentials expired. DNS-01 uses an API token; a rotated token or changed provider stops renewal. The dry run reports it.
- A forgotten subdomain on a box nobody remembers. Certificate transparency search finds it.
- Renewed on disk, old in memory. No reload hook. Test it once with
--force-renewal.
Verify
- The SSL checker shows the certificate valid for more than 30 days, the chain validating, and the site served over HTTPS.
sudo certbot renew --dry-run(or your stack's equivalent) succeeds and the timer's next run is in the future.- After the next real renewal, the served certificate's date has moved; an unchanged date means the reload hook is missing.
- Your monitor has your address and a test alert reached it.
Questions people ask
Can I renew an SSL certificate before it expires?
Yes, and you should. Automated clients renew when about a third of the lifetime is left, and a manual renewal can happen any time. With Let's Encrypt and other ACME CAs the new certificate is valid from issue, so renewing early costs nothing. Some commercial CAs add remaining days to a renewal ordered early, but new CA/Browser Forum limits cap the total lifetime.
Why did my SSL certificate not renew automatically?
Usually one of five things: the renewal timer or cron job no longer runs, port 80 is blocked so the HTTP-01 challenge fails, DNS API credentials expired, a stale subdomain made the whole request fail, or the certificate renewed but the web server was never reloaded. Run sudo certbot renew --dry-run or your stack's test command; it names the failing step in one line.
Does renewing an SSL certificate cause downtime?
No, if the server reloads rather than restarts. A reload (systemctl reload nginx, apachectl graceful, Caddy's automatic swap) loads the new certificate while existing connections finish, so visitors notice nothing. Downtime happens only when renewal is missed and the old certificate expires, or when a manual install uses the wrong file, such as a certificate without its intermediate.
Do I need a new CSR to renew an SSL certificate?
For a manual renewal, usually yes: most CAs ask for a CSR, and generating a new private key with it is good practice. ACME clients such as certbot create the key and CSR for you on every renewal, so there is nothing to do by hand. Keep the private key on the server, never e-mail it, and install it together with the new certificate.