EXERCISE 3 — Why a cert expired despite "certbot being set up" ============================================================== "certbot ran once and got a cert" is NOT the same as "renewal works forever." Here are the most likely causes and the fixes. CAUSE 1 — the renewal timer/cron isn't actually running. - certbot normally installs a systemd timer (certbot.timer) or cron job that runs `certbot renew` twice a day. If the package was installed in a way that skipped this, or the timer was disabled, nothing ever renews and the 90-day cert simply expires. - Check: systemctl list-timers | grep certbot systemctl status certbot.timer - Fix: systemctl enable --now certbot.timer CAUSE 2 — the server never reloaded the renewed cert (the classic one). - `certbot renew` DID fetch a fresh cert to disk, but the running web server (nginx/apache) still holds the OLD cert in memory. With no reload, visitors keep being served the expiring cert until it dies — even though the files on disk are current. This is why "certbot said it renewed" yet the site shows an expired cert. - Fix: a DEPLOY HOOK that reloads the server after each successful renewal: certbot renew --deploy-hook "systemctl reload nginx" (or place a script in /etc/letsencrypt/renewal-hooks/deploy/). The hook runs ONLY when a cert was actually renewed. CAUSE 3 — the validation challenge now fails at renewal time. - Renewal re-runs domain validation. It can break if the conditions changed: the .well-known/acme-challenge path is no longer served (HTTP-01), an HTTP->HTTPS redirect or firewall now blocks the CA's check, the DNS TXT automation broke (DNS-01), or the domain's DNS/host moved. - Fix: ensure the challenge method still works in the current setup; for HTTP-01 keep the ACME path reachable over plain HTTP. HOW THE TWO SAFEGUARDS WOULD HAVE PREVENTED IT: - `certbot renew --dry-run` exercises the ENTIRE renewal + validation flow against the staging environment WITHOUT issuing a real cert or touching rate limits. Running it after setup (and periodically) would have surfaced Cause 1 and Cause 3 long before the real cert expired — a green dry-run means renewal will actually succeed. - A DEPLOY HOOK (`--deploy-hook "systemctl reload nginx"`) directly fixes Cause 2: every successful renewal automatically reloads the server, so the new cert is actually served instead of sitting unused on disk. ONE-LINE LESSON: Getting a cert is step one; PROVE renewal works end-to-end (dry-run) and ensure the server RELOADS the new cert (deploy hook). Otherwise a "set-and-forget" setup quietly expires in 90 days.