先跑 certbot certificates 看证书的真实到期时间,再 certbot renew --dry-run -v 定位是哪个域名、哪种挑战报错,最后翻 /var/log/letsencrypt/letsencrypt.log——命令行那一行 timeout 基本等于没说,日志里才有具体是 404 还是 DNS 解析失败。
dry-run 想现场抓包,加 --debug-challenges,它会挂起等你手动 curl 那个 challenge URL,能直接验证 80 端口和安全组是不是通的,比猜快得多。webroot 路径要和 nginx 里的 root 对齐,被 rewrite 截胡的话 nginx -T | grep -A5 well-known 一搜就现形。另外多域名塞同一张证书是有风险的:只要一个域名验证挂,整张都不续,拆成独立证书反而更稳。
最容易漏的是「续签成功但网站还报旧证书」——八成是没 reload。webroot 模式不会自动重载,得挂 --deploy-hook "systemctl reload nginx";用 nginx 插件才会帮你做。还有 cron 环境变量的问题,除了写全 /usr/bin/certbot,更省事的做法是直接用 certbot 自带的 systemd timer(snap 装的话 systemctl list-timers | grep certbot 看一眼),别自己再塞个 cron 进去打架。
告警我一般不用邮件,写个脚本 openssl s_client -connect 域名:443 2>/dev/null | openssl x509 -noout -enddate 丢进监控,比等 certbot 报错早好几天发现。你提的时间同步那条确实阴,NTP 飘了连 dns-01 的签名都会失败,建议顺手把 chrony 的偏移量也纳入监控。