续签成功却还在用旧证书:Nginx 证书部署后的验证与排错流程
自动续签证书后浏览器仍报过期的常见原因,是证书链没正确加载或部署步骤遗漏。本文按前置条件、操作步骤、验证方法的顺序,给出从签发确认到线上实际生效的完整排查路径。
本文目录

周一大早上班,监控告诉你证书续签成功了,浏览器却还在弹“证书已过期”。ACME 日志一片绿色,运维页面一片红色——这是证书运维里最常见、也最容易让人怀疑人生的场景之一。
先给结论:签发成功 ≠ 部署生效。证书文件躺在磁盘上,和 Nginx 真正把它交出去,中间隔着好几个环节。下面按前置条件、步骤、验证来走一遍完整流程。
前置条件
- 已有一台 Nginx 提供 HTTPS 服务,证书由 ACME 客户端(如 CertbotX)自动签发。
- 有服务器 SSH 权限,能用
nginx -t和openssl。 - 能访问证书实际存放路径(续签和部署往往涉及两个不同位置)。
第一步:确认新证书确实签发出来了
不要先动 Nginx,先看文件本身:
openssl x509 -in /path/to/fullchain.pem -noout -dates -subject -issuer看 notAfter 是否是新的到期时间。如果这里还是旧日期,说明续签根本没拿到新证书,问题出在 ACME 阶段,回去查续签日志(DNS-01 常见原因是 CNAME 委托记录被改动、权威 DNS 超时)。
如果日期是新的,但路径不是你 nginx.conf 里 ssl_certificate 指向的那个——恭喜,找到一半问题了:续签只更新了存储目录,没有同步到 Nginx 引用的位置。
第二步:确认 Nginx 加载的是哪份文件
直接问运行中的 Nginx,而不是凭记忆翻配置:
nginx -T | grep -E "ssl_certificate|server_name"nginx -T 会把包含 include 在内的完整生效配置打出来。确认每条 server 块指向的证书路径,和第一步里新证书的路径一致。路径不一致就改配置或复制文件,然后:

nginx -t && nginx -s reload两个命令一个都不能省。nginx -t 不过就 reload,等于闭着眼睛过河。
第三步:从外部验证,而不是从服务器上自我感觉良好
服务器本地一切正常不代表线上生效。用 s_client 直接看握手时交出的证书:
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -dates -subject注意 -servername 参数:一个 IP 上挂了多个站点时,SNI 决定了返回哪张证书。很多“证书没换”的排查最后发现是请求打到了默认 server 块,拿了另一张旧证书。
如果用了 CDN,还要区分回源证书和边缘证书。在源站 IP 上验证回源证书,在 CDN 域名上验证边缘证书,两者是分开续签、分开部署的,别指望续一个就能好另一个。
在 CertbotX 中实践
这类“续了但没生效”的问题,CertbotX 的设计思路是把签发和部署绑成一条流水线:证书通过 DNS-01 签发后(用 CNAME 委托完成域名验证,不需要暴露站点或改 A 记录),会自动推送到配置的 Agent、EdgeOne 或 CDN 端,并在到期前再次触发整条流程重新签发。每条部署记录都可审计——出问题时先看部署记录里这次推送的目标和结果,比逐台登录服务器查要快得多。但要注意边界:自动部署解决的是“文件有没有推到位”,第三步那种 SNI 和 server 块归属的问题,还是得靠 s_client 自己验。
小坑备忘
- HSTS 开着的站点:浏览器缓存了 HSTS 策略后,部分证书报错页面连“继续访问”的按钮都没有,排查时建议先用
curl -k或openssl排除浏览器因素。关于 HSTS 行为细节见 MDN 的说明。 - fullchain 和 cert.pem 混用:
ssl_certificate应指向 fullchain,指错了会导致部分旧设备验证链失败,表现为“有些客户端正常、有些报错”,极具迷惑性。 - reload vs restart:reload 是平滑的,但如果新证书文件权限不对(比如 Nginx worker 用户读不到),reload 后旧 worker 退掉、新 worker 起不来时才会暴雷。
nginx -t能提前抓到大部分这类问题。