Certbot renewal

Certbot installs a systemd timer or cron job that runs `certbot renew` twice a day, so renewal is automatic from the moment the first certificate is issued and no manual command is normally needed. `certbot renew` is deliberately a no-op until a certificate is within 30 days of expiry, which means a successful run that renews nothing is the expected result rather than a failure. Verify the whole path end to end with `certbot renew --dry-run`, which exercises renewal against the staging environment without consuming rate limits. The most common real failure is not renewal itself but the reload that should follow it: the certificate on disk is new, the running web server still holds the old one in memory, and the fix is a deploy hook in `/etc/letsencrypt/renewal-hooks/deploy/` that reloads the service.

Updated August 19, 2026 Verified against OpenSSL 3.5.7

Renewal is already automatic #

Installing Certbot installs a scheduler. On a systemd distribution that is certbot.timer, on a snap install snap.certbot.renew.timer, and elsewhere /etc/cron.d/certbot. Each runs certbot renew twice a day at a randomised minute.

Is the timer active?
systemctl list-timers | grep -i certbot
Expected output
Sat 2026-08-22 04:17:33 UTC  8h left  certbot.timer  certbot.service

certbot renew renews nothing until a certificate is within 30 days of expiry. A run that reports No renewals were attempted is working correctly.

Check what is actually managed #

Every lineage, its expiry and its files
sudo certbot certificates
Expected output
Certificate Name: example.com
Domains: example.com www.example.com
Expiry Date: 2026-11-04 09:12:44+00:00 (VALID: 76 days)
Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem

Confirm independently what the running server is serving, which is not always the same thing:

When does the certificate on disk expire?
openssl x509 -in certificate.crt -noout -enddate
Will it survive the next 30 days?
openssl x509 -in certificate.crt -noout -checkend 2592000
Expected output
Certificate will not expire

That exits non-zero when the certificate will expire inside the window, which makes it usable directly as a monitoring check.

Test the whole path without spending anything #

A real renewal against the staging environment
sudo certbot renew --dry-run

This performs an actual challenge, so it catches a firewalled port 80, expired DNS credentials, a webroot that moved and a plugin that vanished in a distribution upgrade — the four things that break renewal months after issuance. It consumes no rate limit.

The failure that is not a renewal failure #

The single most common report is “Certbot renewed the certificate but the site still serves the old one”. Nothing is wrong with renewal. Web servers read certificates into memory at startup, and a new file on disk is invisible until the process reloads.

Certbot runs every executable in the deploy-hook directory only when a certificate was actually renewed, which is exactly the right trigger:

Reload nginx after any successful renewal
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh >/dev/null <<'EOF'
#!/bin/sh
systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

When renewal genuinely fails #

Read the log first; it names the challenge that failed and why:

sudo tail -50 /var/log/letsencrypt/letsencrypt.log
Symptom in the log Cause Fix
Timeout during connect on HTTP-01 Port 80 closed or firewalled Open port 80; the challenge needs it even on an HTTPS-only site
404 fetching the challenge file Webroot moved, or an alias intercepts /.well-known/ Correct webroot_path in the renewal config
NXDOMAIN / DNS-01 failures DNS API credentials expired or rotated Renew the credentials file named in the renewal config
unauthorized after a working year The domain no longer resolves to this host Point DNS back, or remove the lineage
too many certificates already issued Duplicate-certificate rate limit Wait; stop using --force-renewal
Could not choose appropriate plugin Authenticator plugin removed by a distro upgrade Reinstall the plugin package

The renewal configuration is a plain file, and editing it is the supported way to change how a lineage renews:

sudo cat /etc/letsencrypt/renewal/example.com.conf

Point the server at the right file #

Certbot writes four files per lineage. Which one you reference matters:

File Contents Use it for
fullchain.pem Leaf plus intermediates nginx ssl_certificate, Apache SSLCertificateFile
cert.pem Leaf only Almost nothing — produces an incomplete chain
chain.pem Intermediates only Legacy SSLCertificateChainFile on Apache < 2.4.8
privkey.pem The private key ssl_certificate_key

Serving cert.pem is the other half of this trap: the site loads in a browser, which repairs the missing intermediates itself, and fails for curl, mobile apps and monitoring with unable to get local issuer certificate.

Wildcards renew differently #

A wildcard lineage can only be validated over DNS-01, so its renewal depends on DNS API credentials that no one thinks about until they expire. The renewal config records which plugin and credentials file to use, and --dry-run is the only way to find out that they have stopped working before the certificate does. See wildcard certificates for why the challenge type is forced.

Frequently asked questions

certbot renew says "No renewals were attempted". Is that a failure?
No, it is the normal result. Certbot only renews inside the last 30 days of a 90-day certificate, so most runs correctly do nothing. Use certbot renew --dry-run to exercise the path regardless of expiry.
The certificate renewed but my site still serves the old one. Why?
nginx, Apache and HAProxy read certificates into memory at startup. A new file on disk changes nothing until the service reloads. Add a deploy hook that reloads it — that step is missing far more often than renewal itself fails.
Do I need a cron job? Every guide adds one.
Almost certainly not. Package and snap installations both ship a timer that already runs renewal twice a day, and adding a second scheduler means two processes competing for the same lock. Check with systemctl list-timers before writing one.
Should nginx point at cert.pem or fullchain.pem?
fullchain.pem. It contains the certificate followed by the intermediates; cert.pem is the leaf alone, and serving it produces an incomplete chain that browsers hide and every other client rejects.
Can I copy the files out of /etc/letsencrypt/live/?
Point at them, do not copy them. The files there are symlinks into archive/ that Certbot repoints on each renewal, so a copy is a snapshot that silently goes stale while the symlink stays current.
What does --force-renewal cost?
It issues a new certificate regardless of expiry, which counts against the duplicate-certificate rate limit. Use it to recover from a genuinely broken certificate, not as a way to test renewal — --dry-run exists for that and is free.

References