服务器迁移后 Let's Encrypt 证书续期失败的排查与修复
服务器迁移后,应用启动、数据库连接、Nginx 转发和 DNS 切换都检查通过了,但 90 天后 Let’s Encrypt 证书却在续期时直接失败。排查发现,续期脚本依赖的旧 webroot 路径在迁移中被忽略。
迁移检查清单里通常漏掉证书续期
大多数开发者在做服务器迁移时,注意力集中在核心服务是否可用。应用能不能正常启动,数据库连接字符串是否更新正确,Nginx 的 upstream 和 location 配置有没有同步,DNS 记录是否已经切到新 IP,这些都是标准检查项。信号中提到的迁移场景正是如此:团队把这些点逐一验证后,认为迁移已经完成。
然而证书续期机制却常常被遗忘。Let’s Encrypt 证书有效期只有 90 天,依赖自动续期任务在到期前 30 天左右触发。迁移时如果只关注运行时状态,没有检查定时任务和证书客户端配置,问题就会在 90 天后集中爆发。旧服务器上的 certbot cron 任务可能还在新服务器上指向不存在的路径,导致 renew 命令直接报错。
这种遗漏的根本原因是证书续期不属于“即时可见”的故障。应用启动失败立刻能看到,证书过期却要等到浏览器警告或服务中断才显现。很多团队把证书管理当作一次性操作,忽略了它实际上是一个持续运行的自动化流程。迁移清单里增加证书相关检查,能大幅降低后续故障。
实际案例中,开发者往往在迁移完成后几个月才发现证书无法续期。这时再回溯配置变更,成本远高于提前验证。把证书续期纳入迁移 checklist,是避免类似问题的第一步。
ACME HTTP-01 challenge 依赖的路径在迁移后失效
Let’s Encrypt 使用 ACME 协议完成域名所有权验证,其中最常用的是 HTTP-01 challenge。certbot 在 renew 时会把特定 token 文件写入 .well-known/acme-challenge 目录,Let’s Encrypt 服务器再通过 HTTP 请求拉取该文件完成验证。
迁移过程中,如果新服务器的 webroot 路径与旧服务器不一致,而续期命令仍使用旧的 –webroot-path 参数,challenge 文件就无法被正确放置。信号中的排查案例显示,续期脚本直接报错 “Failed to renew certificate”,根源正是这个路径变更。
certbot renew 默认会复用上次签发时的配置。如果迁移时只复制了 /etc/letsencrypt 目录下的密钥和证书,没有同步 certbot 的 renewal 配置文件,路径信息就会保持为旧值。新服务器上这个目录可能不存在,或者权限不同,导致写入失败。
HTTP-01 的整个流程高度依赖文件系统路径。哪怕应用本身能正常响应 80 端口请求,只要 challenge 目录不对,验证就会失败。这也是为什么很多迁移后的服务表面正常,证书却悄无声息地停止续期。
端口 80 限制和 DNS 记录变更阻断自动续期
除了路径问题,ACME 验证还受网络层配置影响。HTTP-01 challenge 要求服务器在 80 端口开放访问。如果新服务器防火墙只允许 443 端口,或者云服务商的安全组规则没有放开 80,Let’s Encrypt 的验证请求就无法到达。
DNS 记录变更也会带来问题。如果迁移后 DNS 尚未完全生效,或者存在缓存,验证服务器可能仍然解析到旧 IP,导致请求发到已经下线的机器。信号提到的常见失效原因中,端口限制和 DNS 配置是除路径外最频繁出现的两类。
部分国内服务器还会遇到运营商级别的 80 端口管控,或者使用 CDN 后 challenge 路径被 CDN 规则拦截。这些因素叠加,使得自动续期在迁移场景下格外脆弱。
即使 certbot 配置正确,只要网络层面有一处阻断,续期就会失败。排查时不能只看本地日志,还需要确认外部验证请求是否能正常抵达。
迁移后证书状态的四步排查流程
第一步是检查当前证书有效期。运行 certbot certificates 或直接查看 /etc/letsencrypt/live/example.com/fullchain.pem 的过期时间,确认是否已经接近或超过 90 天。
第二步查看续期日志。cat /var/log/letsencrypt/letsencrypt.log 能给出具体错误信息,通常会指出路径不存在、权限拒绝或连接超时。信号中的真实迁移排查正是从日志入手,快速定位到 webroot 问题。
第三步确认配置路径。进入 /etc/letsencrypt/renewal/ 目录,打开对应域名的 conf 文件,检查其中的 webroot_path、authenticator 等参数是否与当前服务器环境匹配。
第四步手动测试 challenge。使用 certbot certonly --webroot -w /var/www/html -d example.com --dry-run 进行模拟续期,观察是否能成功创建 .well-known/acme-challenge 文件并通过验证。这一步能直接验证配置和网络是否可用。
这四步按顺序执行,可以在最短时间内定位问题所在,避免盲目尝试。
重新注册 webroot 并恢复定时续期任务
定位到路径问题后,需要重新注册正确的 webroot。执行 certbot certonly --webroot -w /new/webroot/path -d example.com 使用新路径完成一次验证,certbot 会更新 renewal 配置。
之后运行 certbot renew --dry-run 测试自动续期逻辑是否恢复正常。如果成功,再执行真实续期 certbot renew。
定时任务也需要更新。检查 crontab 或 systemd timer,确保续期命令使用正确的参数。常见做法是每天凌晨运行 certbot renew --quiet,并在成功后执行 nginx reload。
修复完成后,建议立即触发一次续期并观察日志,确认新配置已生效。信号中的修复流程显示,更新 webroot 并调整 cron 后,证书续期恢复正常。
整个过程不需要重新申请证书,只需修正配置即可。后续迁移时提前把 renewal 目录和定时任务纳入同步清单,能避免重复劳动。
中文开发者迁移时需额外检查的三个配置项
国内服务器环境有自身特点,首先是路径规范。很多团队使用 /data/wwwroot 或 /home/wwwroot 作为 webroot,迁移时新旧路径差异更大,必须手动确认 renewal 配置中的 webroot_path。
其次是权限问题。certbot 进程通常以 root 运行,但应用可能以 www-data 用户运行。迁移后目录权限如果没有同步,challenge 文件写入就会失败。建议统一使用 755 权限并确保 certbot 可写。
最后是 systemd timer 的使用。在使用 Ubuntu 20.04+ 或 CentOS 7+ 的服务器上,推荐用 systemd timer 替代 crontab。检查 /lib/systemd/system/certbot.timer 是否存在,并确认其与迁移后环境匹配。国内很多云主机默认未启用 timer,需要手动启动并设置开机自启。
这三个配置项是中文开发者在迁移 Let’s Encrypt 证书时最容易踩坑的地方。提前检查,能显著降低续期失败概率。
通过这次真实案例可以看出,证书续期机制虽然自动化程度高,但在服务器迁移这类变更场景下仍需人工干预。把 ACME 验证依赖的路径、网络、权限和任务配置纳入迁移流程,是保障证书长期有效的关键。
参考来源
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/ai001/post/20260903/%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%81%E7%A7%BB%E5%90%8E-Lets-Encrypt-%E8%AF%81%E4%B9%A6%E7%BB%AD%E6%9C%9F%E5%A4%B1%E8%B4%A5%E7%9A%84%E6%8E%92%E6%9F%A5%E4%B8%8E%E4%BF%AE%E5%A4%8D/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com