Auto-Renewing SSL Certificates
Let’s Encrypt SSL certificates are free, but they are short-lived: each one is valid for only 90 days. SSL (Secure Sockets Layer, the technology that encrypts traffic between a browser and your server, now technically called TLS) certificates that expire will cause every visitor to see a scary “Your connection is not private” warning. The good news is that Certbot (the official tool from Let’s Encrypt for getting and renewing certificates) sets up automatic renewal for you. This page explains how that automation works, how to test it, and how to confirm it is actually running so you never get caught by a surprise expiry.
Why certificates expire so quickly
Let’s Encrypt deliberately uses a short 90-day lifetime. Short-lived certificates limit the damage if a private key (the secret file that proves your server owns the certificate) is ever stolen, and they force everyone to automate renewal instead of doing it by hand once a year. The trade-off is that you cannot “set and forget” a certificate for long. Renewal must happen automatically, well before the 90 days run out.
Certbot is smart about timing. When you run a renewal, it only actually renews certificates that are within 30 days of expiring. So even though the renewal job runs often, it does nothing most of the time and only acts when a certificate is genuinely close to expiry.
How automatic renewal works
When you installed Certbot (usually with sudo apt install certbot on Ubuntu, or the Nginx/Apache plugin package), it installed a renewal mechanism for you. On modern Ubuntu (22.04 LTS and 24.04 LTS) this is a systemd timer.
A systemd timer is the modern replacement for a cron job (an older Linux scheduler that runs commands at fixed times). The timer is built into systemd, the system manager that starts and supervises services on Ubuntu. It schedules a small task that runs certbot renew twice a day at randomized times.
The randomized timing is intentional. If millions of servers all hit Let’s Encrypt at exactly midnight, they would overload the service. Certbot spreads requests out, so do not be alarmed if your timer fires at an odd minute.
Systemd timer vs cron — which do you have?
| Mechanism | Where it lives | When it is used |
|---|---|---|
systemd timer (certbot.timer) | /lib/systemd/system/certbot.timer | Default on Ubuntu 22.04 / 24.04 with the apt package |
| cron job | /etc/cron.d/certbot | Older systems, or if systemd timers are unavailable |
On a standard modern Ubuntu server you will use the systemd timer. If both exist, that is fine — the cron entry checks for systemd and skips itself to avoid running renewal twice.
Checking that the timer is active
The single most important habit is to verify the timer is actually scheduled. Run this command to list all active timers.
systemctl list-timers
Output:
NEXT LEFT LAST PASSED UNIT ACTIVATES
Mon 2026-06-16 09:42:18 UTC 5h 12min left Sun 2026-06-15 21:14:03 UTC 6h ago certbot.timer certbot.service
Mon 2026-06-16 06:11:00 UTC 1h 41min left Mon 2026-06-16 03:00:11 UTC 1h 29min ago apt-daily.timer apt-daily.service
Look for certbot.timer in the UNIT column. The NEXT column tells you when it will run next, and LAST tells you when it last ran. If certbot.timer does not appear at all, the automation is not running and your certificate could expire. You can also check the timer directly.
sudo systemctl status certbot.timer
Output:
● certbot.timer - Run certbot twice daily
Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Sun 2026-06-15 04:01:55 UTC; 1 day 3h ago
Trigger: Mon 2026-06-16 09:42:18 UTC; 5h 12min left
Triggers: ● certbot.service
The two words to look for are enabled (it will start on boot) and active (waiting) (it is running and waiting for its next trigger). If it says disabled, enable it.
sudo systemctl enable --now certbot.timer
Testing renewal without changing anything
You do not have to wait 60 days to find out whether renewal works. Certbot has a dry-run mode that goes through the entire renewal process against Let’s Encrypt’s staging (test) servers, but does not save or install any new certificate. This is the safest way to confirm everything is wired correctly.
sudo certbot renew --dry-run
Output:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Processing /etc/letsencrypt/renewal/example.com.conf
Account registered.
Simulating renewal of an existing certificate for example.com
Congratulations, all simulations of the renewals succeeded:
/etc/letsencrypt/live/example.com/fullchain.pem (success)
If you see “all simulations of the renewals succeeded”, your automatic renewal is healthy. If it fails, the error message will usually tell you why — most commonly a firewall blocking port 80, or a web server config that no longer matches.
Do not run
certbot renew(without--dry-run) over and over to test things. The real Let’s Encrypt service has rate limits, and you can lock yourself out of issuing certificates for that domain for up to a week. Always use--dry-runfor testing.
What happens when renewal succeeds
When certbot renew actually renews a certificate, the new certificate files are written into /etc/letsencrypt/live/<your-domain>/. But your web server (Nginx or Apache) loaded the old certificate into memory when it started, so it needs to be told to reload to pick up the new files.
Certbot handles this with deploy hooks — small commands it runs automatically after a successful renewal. If you installed the certificate using the Nginx or Apache plugin, the reload hook is set up for you. You can confirm it by checking the renewal config file.
sudo cat /etc/letsencrypt/renewal/example.com.conf
Output:
renew_before_expiry = 30 days
version = 2.11.0
archive_dir = /etc/letsencrypt/archive/example.com
cert = /etc/letsencrypt/live/example.com/cert.pem
...
[renewalparams]
authenticator = nginx
installer = nginx
If installer = nginx (or apache) is present, the reload happens automatically. If you obtained your certificate with the --webroot or --standalone method, you may need to add a deploy hook yourself so the web server reloads.
sudo certbot renew --dry-run --deploy-hook "systemctl reload nginx"
What happens if renewal fails
If a renewal attempt fails, Certbot does not give up — the timer runs twice a day, so it will simply try again on the next run. Because renewal starts 30 days before expiry, that gives you roughly 60 chances to fix the problem before the certificate actually expires.
To see what happened, read Certbot’s log file.
sudo tail -n 40 /var/log/letsencrypt/letsencrypt.log
The most common causes of failure are:
- Port 80 is blocked. Let’s Encrypt validates your domain over HTTP. Make sure your firewall allows it with
sudo ufw allow 80/tcp. - DNS no longer points to this server. If you moved servers, the domain’s A record must point to the new IP.
- The web server config was deleted or renamed. Certbot needs the original site config to validate.
If you want an early warning, Let’s Encrypt emails the address you registered with about 20 days before expiry if renewal has not happened. Keep that email address valid.
Best practices
- Run
sudo certbot renew --dry-runright after issuing a certificate to confirm renewal works end to end. - Check
systemctl list-timersoccasionally to make surecertbot.timeris still scheduled andenabled. - Keep port 80 open in
ufw— Let’s Encrypt needs it for HTTP validation even if your site only serves HTTPS. - Use a real, monitored email when registering so you receive expiry warnings.
- Never disable the timer or delete
/etc/cron.d/certbotto “clean up” — that is what keeps your site secure. - After any change to your Nginx or Apache config, re-run a dry run to confirm renewal still passes.