证书过期前该怎么排查

工具相关 ·

某天早上,用户反馈网站打不开,浏览器显示「您的连接不是私密连接」。登录服务器一看,证书昨天到期了。这类事故的根因往往不是技术问题,而是没人知道证书什么时候到期——续期动作没有被安排,或者安排了但没确认是否真的生效。

有效期字段怎么读

证书里有两个时间字段:生效时间*(notBefore)和*过期时间(notAfter)。

判断状态的方法很简单:把当前时间与这两个时间比较。

当前时间 < notBefore  → 尚未生效
notBefore ≤ 当前时间 ≤ notAfter  → 有效
当前时间 > notAfter  → 已过期

解析工具通常会把状态做成徽章,方便一眼看出:剩余多少天、是否即将过期、是否已过期、是否尚未生效。

其中「剩余不足 30 天」通常会被标黄提醒。这个阈值的意义在于留出处理时间——续期、部署、验证都需要时间,等到只剩几天再处理风险太高。

有效期为什么越来越短

有一个趋势值得注意:证书的有效期在持续缩短。

早些年商业证书的有效期通常是 1 年,后来逐步缩短。Let's Encrypt 提供的免费证书从一开始就是 90 天。而行业规范也在推动更短的有效期。

缩短有效期的动机是安全:有效期越短,证书被泄露或私钥被攻破后的影响窗口越小。同时它也强制推动了自动化续期——90 天的周期下,手工续期不现实。

所以现在部署证书时,自动续期不是可选项而是必需项。Let's Encrypt 的官方客户端支持自动续期,配合定时任务可以做到无人工干预。商业证书虽然有效期长一些,但也应该配置到期提醒。

常见的过期原因

即使配置了自动续期,仍然会出问题。常见的原因有几类。

自动续期任务没运行。定时任务被误删、服务器迁移后忘了重新配置、或者续期脚本因为权限问题静默失败。这类问题的特点是「以为配好了,实际没跑」。

续期成功但没重载服务。证书文件更新了,但 Web 服务器还在用内存里加载的旧证书。Nginx 需要执行 reload 才能读取新证书。所以续期脚本里必须包含重载这一步。

多节点只更新了部分。如果站点部署在多个服务器或 CDN 节点上,证书需要同步到所有节点。只更新了其中一台,其他节点仍会返回过期证书。而用户访问到哪台是随机的,所以表现为「时好时坏」。

证书链不完整。这不是过期问题,但症状相似——浏览器可能报证书错误。原因是服务器只发送了域名证书,没有发送中间证书。有些浏览器能自己补全,有些不能。

域名变更后证书没跟着更新。新增了子域名,但证书里没有包含,访问新域名时报名称不匹配。这个问题的排查方法前面讨论过——看 SAN 列表。

怎么建立有效的监控

避免证书事故的关键是独立于证书本身的监控。

如果只靠「用户反馈」发现问题,那问题已经发生了。有效的做法是主动探测:

外部探测。用一个独立的服务定期访问站点,检查返回的证书信息,包括有效期、颁发者、SAN 列表、指纹。一旦发现剩余天数低于阈值或指纹变化,就告警。

多节点探测。如果有多个服务器或 CDN 节点,需要分别探测。因为不同节点可能加载不同的证书。探测方式可以是直接访问各节点的 IP 并指定 Host 头。

监控指纹变化。指纹变化说明证书被更换了。如果这个更换不是预期的,需要立刻排查——可能是配置被误改,也可能是被替换成了其他证书。

监控到期时间而不是剩余天数。告警条件应该是「到期时间早于某个日期」,而不是「剩余天数少于 N 天」。因为剩余天数的计算依赖探测时刻,而到期时间是一个固定的属性。

排查时的一个顺序

当收到「证书有问题」的反馈时,建议按这个顺序检查。

先确认现象的具体表现:是「已过期」还是「名称不匹配」还是「不受信任」。三种情况的原因完全不同。

然后解析实际返回的证书,看它的有效期、SAN、颁发者、指纹。注意要看服务器实际返回的证书,而不是服务器上存放的证书文件——两者可能不一致(比如配置指向了另一个路径)。

再看证书链是否完整。有些工具会检查服务器是否发送了完整的链。

最后确认所有节点是否都已更新。逐个节点访问,比对返回的证书指纹是否一致。

检查清单

  • 证书状态由 notBefore 与 notAfter 与当前时间的比较决定
  • 剩余不足 30 天应标黄提醒,留出处理时间
  • Let's Encrypt 证书有效期 90 天,自动续期是必需项
  • 常见原因包括续期任务未运行、续期后未重载服务、多节点未同步
  • 监控应独立于证书本身,做外部主动探测
  • 多节点场景要分别探测,并监控指纹变化
  • 排查时看服务器实际返回的证书,而不是存放的证书文件
阅读 12