2027 年 3 月 15 日起,新签发的公开 SSL 证书有效期最长 100 天,2029 年 3 月 15 日起再缩到 47 天。第一步已经走完:今年 3 月 15 日以后签发的证书,最长只有 200 天。
以前一张证书一年换一次,到 2027 年一年至少换 4 次,2029 年差不多每月一次。每换一次都要 reload 一次服务,而 reload 正好是运维最不愿意频繁做的操作。
时间表
CA/B 论坛在 2025 年 4 月通过了 SC-081v3 提案,所有公开信任的 CA 都要执行,付费证书也一样:
| 生效日期 | 证书最长有效期 | 域名验证结果可复用 |
|---|---|---|
| 2026-03-15 | 200 天 | 200 天 |
| 2027-03-15 | 100 天 | 100 天 |
| 2029-03-15 | 47 天 | 10 天 |
第三列容易被忽略。CA 验证过一次你对域名的控制权后,这个结果可以在一段时间内复用,签下一张证书时不用再验证。到 2029 年这个期限只剩 10 天,几乎每签一张证书都要重新验证一次。现在靠邮件验证、手动传验证文件买付费证书的,到时候每个月都要走一遍这套流程。
一年一次的时候,问题是记不住
一年换一次的证书,提醒很难定。在手机里设一个一年后的提醒事项,到时候手机可能都换了。日历和工单系统也差不多,一年时间足够让负责的人换岗。
如果你以前靠 Let's Encrypt 的到期邮件兜底,这封邮件从 2025 年 6 月 4 日起已经停发了。
所以过期往往是用户先发现的。我们碰到比较多的是微信小程序:客户反馈“提示网络出问题,小程序用不了”,没有任何地方提到证书。排查时先看服务端日志,会发现这些请求一条记录都没有。原因是证书过期后,客户端在 TLS 握手阶段就断开了,请求根本到不了 Nginx。
小程序或 App 报网络错误、服务端日志里又没有对应请求时,先查证书:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -enddate
不想登录服务器的话,也可以用 SSL 证书到期检测 直接查。
100 天以后,问题变成每次都要 reload
我们之前的证书大多部署在阿里云 ECS 上,后来逐步挪到了全站加速。在全站加速控制台换证书,只是上传一下,不用登录服务器,也不用重启服务。
在服务器上换证书,麻烦的地方在 reload。两件事让人心里没底:
- 不确定 Nginx 配置有没有被别人改过。配置文件里的问题平时不会暴露,下一次 reload 才会爆出来,而这次 reload 恰好是你为了换证书执行的。
- 有些服务器很久没动过,突然要 reload 甚至 restart,谁也说不准会不会带出别的问题。
一年一次的时候,这种风险一年碰一次,咬咬牙也就过去了。有效期变成 100 天,每台服务器每年要面对四五次;到 47 天,每个月一次。CA/B 论坛缩短有效期的理由是吊销机制不好用,证书泄露后影响时间越短越好,这个道理没错。但对运维来说,这就是实打实多出来的活和风险。
为什么很多运维宁可手动
阿里云有证书自动部署,但只对付费证书开放。自己动手操作两下就能省下这笔钱,大部分人不会为此去买证书。
自己写脚本,很多人也不愿意。担心的点很具体:
- 服务器环境和配置会变,脚本没有跟着改,执行起来可能比手动出的事更大。
- 手动换的时候,自己知道是什么时候操作的,换完会亲自测一遍。交给脚本,它可能在半夜执行失败,没人能及时处理。
这些顾虑是成立的。acme.sh 和 certbot 把签发和续期做得很成熟,定时检查、到期前自动续、续期后执行 reload 钩子都有,单机场景的细节可以看 Let's Encrypt 证书自动续期和部署怎么做。但上面两个顾虑,它们管不到:
- 失败了谁知道:certbot 没有失败通知;acme.sh 有通知钩子,但要自己配。
- 部署到云产品:证书要换到全站加速、CDN、负载均衡上,大多还得自己写脚本调用云厂商的 API。环境一变脚本就失效,说的正是这一段。
手动的顾虑没有错,但有效期到 100 天以后,手动的次数撑不住,自动化迟早要上,只是得先满足下面这条。
自动化至少要做到:可以失败,但别动线上
我们给自动化定的标准只有一条:它可以失败,但一定不要影响线上服务,要么成功替换,要么就不要动。
签发失败、部署失败都能接受。证书提前 30 天续期,失败了还有几周时间处理,半夜失败也不要紧,第二天看到通知再处理就行。不能接受的是替换到一半,线上服务跟着坏了。
服务只在 reload 或 restart 时重新读取证书文件。所以只要做到下面几点,部署失败就不会影响线上:
- 替换前先确认新证书和私钥是配对的。
- 备份旧文件,再原地覆盖。用
cat >原地写入,文件的属主、权限和软链接都保持不变;先写临时文件再mv会把这些都换掉。 - reload 前先跑
nginx -t。检查不通过就恢复旧文件,不执行 reload。 - 失败时通知到人。
自己在服务器上换的话,可以参考这段脚本:
#!/usr/bin/env bash
set -euo pipefail
CERT=/etc/nginx/ssl/example.com.pem
KEY=/etc/nginx/ssl/example.com.key
NEW_CERT=$1
NEW_KEY=$2
# 新证书和私钥的公钥必须一致
if [ "$(openssl x509 -noout -pubkey -in "$NEW_CERT" | openssl sha256)" != \
"$(openssl pkey -pubout -in "$NEW_KEY" | openssl sha256)" ]; then
echo "证书和私钥不匹配,未做任何改动" >&2
exit 1
fi
cp -a "$CERT" "$CERT.bak"
cp -a "$KEY" "$KEY.bak"
if cat "$NEW_CERT" > "$CERT" && cat "$NEW_KEY" > "$KEY" \
&& nginx -t && systemctl reload nginx; then
echo "已替换"
else
cat "$CERT.bak" > "$CERT"
cat "$KEY.bak" > "$KEY"
echo "替换失败,已恢复旧证书" >&2
exit 1
fi
脚本失败时会以非 0 退出,配合 cron 的 MAILTO,或者在 else 分支里调一次钉钉、飞书的 Webhook,就能通知到人。Tomcat 这类需要 restart 的服务,恢复旧文件后还要再 restart 一次,否则服务会停在那里。
换到云产品上,情况简单一些。以阿里云全站加速为例,证书通过一次 API 调用整体替换,调用失败时线上还是旧证书,不会出现换了一半的情况。
不想自己维护脚本的话
也可以交给 LapseZero。它用 Let's Encrypt 等免费 CA 签发证书,到期前自动续期,再部署到服务器,或者阿里云、腾讯云、AWS 的 CDN、负载均衡上。
部署到服务器时,它做的和上面的脚本差不多:先备份现有文件,全部写完再执行部署后命令;中途失败就恢复旧文件;部署后命令失败,恢复文件后会再执行一次,把服务拉回旧证书,然后通知你“已回滚,线上仍是旧证书”,等你看过原因再手动重试。部署后命令同样建议带上 nginx -t。