Certbot renewals that reload nginx on their own
TL;DR: Certificates from certbot certonly renew, but nginx keeps serving the old one until reloaded. Put an executable script in /etc/letsencrypt/renewal-hooks/deploy/ that runs nginx -t && systemctl reload nginx, and test it with certbot renew --dry-run --run-deploy-hooks.
Certbot's systemd timer renews certificates fine. The catch: if you got the certificate with certonly, nothing tells nginx to load the new file, and it keeps serving the old one until the next restart. You find out about 90 days later.
The fix
Drop a script into the deploy hook folder. Certbot runs everything in it after each successful renewal, and only then.
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh <<'SH'
#!/bin/sh
nginx -t -q && systemctl reload nginx
SH
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
The nginx -t guard matters: if a broken config is lying around, the reload would fail anyway, and this way the hook doesn't make things worse.
Check it without waiting three months
sudo certbot renew --dry-run --run-deploy-hooks
systemctl list-timers | grep certbot
Certbot skips deploy hooks on dry runs unless you pass --run-deploy-hooks, which is why the flag is there.