Why automate: the 90-day lifetime forces you to master the flow
Let's Encrypt pushes certificate lifetime down to 90 days not to annoy you but to force you to automate and avoid the classic accident of an old long-lived cert expiring unnoticed. Ninety days means renewing four times a year; remembering by hand almost certainly fails, so automation is the only thing keeping the site up.
The renewal works by reissuing: certbot renew reads every cert due within the next 30 days and walks a fresh issuance to swap in a new one. Anything still comfortably valid is skipped, so running renew weekly is entirely safe.
certbot --version
sudo certbot certificates
# Do a dry run to see whether it would reissue
sudo certbot renew --dry-run
# Check the expiry date of each cert
sudo certbot certificates | grep -E "Expiry Date|Certificate Name"Choosing the issuance method: two reasons webroot beats standalone
standalone temporarily binds port 80 and answers validation itself, so if nginx owns 80 or a load balancer sits in front, it either collides or never gets validated correctly. webroot writes a token file into a directory of your choice and lets the already-running web server answer it, changing the least.
For most nginx deployments webroot is the robust default; only when the reverse proxy already routes away / and the acme directory should you consider DNS-01. Its precondition is that nginx points /.well-known/acme-challenge/ at our directory—that is handled as the first step below.
# nginx: route ACME challenge traffic to the webroot
location /.well-known/acme-challenge/ {
root /var/www/certbot;
default_type text/plain;
}
# Directory and permissions
sudo mkdir -p /var/www/certbot/.well-known
sudo chown www-data:www-data /var/www/certbot -R
sudo nginx -t && sudo systemctl reload nginxFirst issuance: point webroot and the domain combo
The key to the issuance command is pairing -w (webroot path) with -d (domain); when one cert spans multiple domains, attach each domain with its own root path, or certbot warns with a "requested /path was not..." style error.
Also nail down the chain: issuance yields fullchain.pem and privkey.pem as the two critical artifacts, which nginx ssl_certificate and ssl_certificate_key point at respectively. Smoke-test https right after generation instead of discovering a broken chain only after config.
sudo certbot certonly --webroot -w /var/www/certbot \
-d example.com -d www.example.com \
-m admin@example.com --agree-tos --no-eff-email
# Verify the artifacts exist
sudo ls -l /etc/letsencrypt/live/example.com/
# Smoke-test right away
curl -sI https://example.com -o /dev/null -w "%{http_code}\n"Wire auto-renewal: certbot.timer plus a cron fallback
The certbot package ships a systemd renew.timer that fires twice a day; on most distros it is enabled out of the box, so verify it is active. If your distro lacks the timer, or you want a fixed schedule that also reloads Nginx, add a cron entry on top.
The deploy hook is an unsung killer: run a reload automatically after a successful renewal so the server never keeps serving the old cert. Below are three parts: checking the timer, a cron line, and the deploy hook.
# Check whether the built-in timer is enabled
sudo systemctl status certbot.timer
# Fallback cron: renew and reload every Monday at 2:30
30 2 * * 1 certbot renew --quiet --deploy-hook "systemctl reload nginx"
# Example deploy hook (drop it in the same dir):
# /etc/letsencrypt/renewal-hooks/deploy/reload-nginx
systemctl reload nginx
# Verify the renewal chain
sudo certbot renew --dry-runMistake vs fix: renewal config pointing at the wrong webroot
A very common trap: the first issuance uses -w to point at the right webroot, later the directory is moved for some reason, but the renewal config keeps the old webroot—so at renewal the ACME challenge 404s and the cert quietly rides toward expiry.
Do not hand-edit the path by heart in /etc/letsencrypt renewal files. Instead read the renewal conf for that cert and correct the installer/webroot fields, or just run certonly again so certbot rewrites it. Then --dry-run to prove the path is right.
# Bad example: move the dir but forget the renewal config
# apt move /var/www/certbot /srv/acme # then forget to update webroot
# Fix comparison: inspect and correct the renewal config
sudo cat /etc/letsencrypt/renewal/example.com.conf | grep -i webroot
# Reissue to rewrite the config
sudo certbot certonly --webroot -w /srv/acme -d example.com --force-renewal
sudo certbot renew --dry-run