How to Renew a Let's Encrypt Certificate Before It Expires
Let's Encrypt certificates expire every 90 days - and a cert that hits zero causes an immediate browser-trust failure in production. The key is renewing at least 30 days before expiry, and automating that renewal so it never relies on memory.
Check the current expiry first
Before renewing, confirm how much time is left:
openssl x509 -in /etc/ssl/api.crt -noout -enddate
Output looks like:
notAfter=Jun 25 10:00:00 2026 GMT
If that date is within 30 days, renew now. Let's Encrypt's own certbot client
will renew automatically when fewer than 30 days remain; triggering it manually
is safe at any point.
Renew with certbot (production path)
On a live server with a domain, certbot renew handles everything - it checks
all installed certs, renews any within 30 days, and reloads the web server:
certbot renew --quiet
Most production setups run this on a systemd timer or cron twice a day:
# /etc/cron.d/certbot
0 */12 * * * root certbot renew --quiet
After renewal, reload your web server to pick up the new cert files:
nginx -s reload
# or
systemctl reload apache2
Generate a cert with openssl (for self-signed or internal CA use)
When you control the CA - on internal networks, staging environments, or when
practicing the renewal workflow - openssl generates the cert directly.
The -days flag is the critical parameter: use 90 to match Let's Encrypt's
lifetime, not a test value like 1:
openssl req -x509 \
-key /etc/ssl/api.key \
-out /etc/ssl/api.crt \
-days 90 \
-subj "/CN=api.example.com"
A -days 1 cert - a common leftover from a test run - looks valid until you
check the expiry and find it is already gone.
Verify the renewed cert
After any renewal, confirm the new expiry before reloading the service:
openssl x509 -in /etc/ssl/api.crt -noout -enddate -subject
Then reload without a full restart so in-flight connections are not dropped:
nginx -t && nginx -s reload
What goes wrong in production
- Wrong
-daysvalue - a cert generated for testing with-days 1gets committed to the renewal script and ships to production. - certbot renewal not automated - the cert was set up manually once and nobody added the cron or systemd timer.
- Web server not reloaded after renewal - certbot renewed the files on disk but nginx is still serving the old cert from memory.
- Port 80 blocked - HTTP-01 ACME challenge fails if a firewall rule closes port 80 before renewal runs.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Checking a certificate's expiry with openssl x509 -noout -enddate
- Setting the correct -days value when generating or renewing a cert
- Automating certbot renew on a cron schedule and reloading nginx after renewal
FAQ
How often do Let's Encrypt certificates expire?
Let's Encrypt certificates are valid for 90 days. certbot recommends renewing when fewer than 30 days remain, so the effective renewal window is every 60 days. Automating renewal with a cron job or systemd timer removes the manual dependency.
How do I renew a Let's Encrypt certificate with certbot?
Run certbot renew - it checks all installed certs and renews any expiring within 30 days. Add --quiet for cron. After renewal, reload your web server (nginx -s reload) to serve the new cert.
How do I check when an SSL certificate expires?
Use openssl x509 -in /path/to/cert.crt -noout -enddate. It prints the notAfter date in UTC. You can also run echo | openssl s_client -connect yourdomain.com:443 2>/dev/null | openssl x509 -noout -enddate to check a live server.
How do I renew a Let's Encrypt certificate?
Run certbot renew - it renews any certificate within 30 days of expiry and reloads the server. Let's Encrypt certs last 90 days, so automate it with a cron job or systemd timer rather than renewing by hand.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →