证书过期这事,一旦发生就是全站级别的红色警告。浏览器直接拦截,访客看到的不是你的网站,是一屏吓人的安全提示。更气人的是它完全可以避免——免费证书加自动续期,配好了就再也不用管。
Let's Encrypt 的证书有效期是 90 天,这个短期限是刻意设计的,目的是逼着大家把续期自动化。Certbot 是它官方推荐的客户端,装完之后会自带一个 systemd timer,每天检查两次,快到期的自动续。你要做的就是确认这个 timer 真的在跑。
这里有个时间点值得记住:从 4.0.0 版本起,Certbot 改成在证书剩余寿命不足三分之一时才真正续期,而不是固定提前 30 天。所以别看到它好几天没动作就以为坏了,那是正常行为。拿不准就用 --dry-run 跑一次演练,它会完整走一遍流程但不写真实证书,也不消耗申请配额。
另一类问题隐蔽得多:证书链不完整。服务器上只配了域名证书,没配中间证书,结果就是有的浏览器正常、有的报错。为什么会这样?因为现代浏览器会缓存中间证书,也会主动去拉取缺失的部分,所以你用自己电脑测可能完全正常,换个环境就挂了。安卓设备和一些老版本 OpenSSL 对这种情况特别敏感。
#!/bin/bash
# SSL 证书体检:链完整性 + 到期天数
DOMAIN="example.com"
PORT="443"
WARN_DAYS=20
# 1. 拉完整证书链,数一数有几层
CHAIN=$(echo | openssl s_client -connect "${DOMAIN}:${PORT}" \
-servername "${DOMAIN}" 2>/dev/null)
echo "$CHAIN" | grep -E "^ *[0-9]+ s:|^ *i:" | head -n 10
# 2. 链是否完整(Verify return code: 0 才是通过)
echo "$CHAIN" | grep -E "Verify return code"
# 3. 到期时间换算成剩余天数
END_STR=$(echo | openssl s_client -connect "${DOMAIN}:${PORT}" \
-servername "${DOMAIN}" 2>/dev/null \
| openssl x509 -noout -enddate | cut -d= -f2)
END_TS=$(date -d "$END_STR" +%s)
NOW_TS=$(date +%s)
LEFT=$(( (END_TS - NOW_TS) / 86400 ))
echo "证书到期:$END_STR"
echo "剩余天数:$LEFT"
if [ "$LEFT" -lt "$WARN_DAYS" ]; then
echo "警告:证书即将到期,请检查 certbot.timer"
systemctl is-active certbot.timer 2>/dev/null
fi
证书链不完整的修法通常是把 fullchain.pem 配上去,而不是 cert.pem。Certbot 签发的目录里这两个文件都在,前者包含了域名证书加中间证书的完整链条,后者只有域名证书。很多教程里图省事写 cert.pem,于是埋下这个雷。Nginx 配置里那行 ssl_certificate 后面跟的必须是 fullchain.pem。
# Nginx HTTPS 配置要点:注意是 fullchain 不是 cert
server {
listen 443 ssl http2;
server_name example.com;
# 必须是 fullchain.pem,只写 cert.pem 会导致证书链不完整
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
# 反代场景下透传协议,否则程序会误判成 HTTP 导致重定向循环
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
续期之后还有一步容易漏:reload Web 服务。证书文件换了,但 Nginx 还握着旧的,不 reload 就不会生效。Certbot 的 deploy hook 就是干这个的,放在 renewal-hooks/deploy 目录下,续期成功自动触发。同样地,--dry-run 演练时 hook 也会执行,正好顺便验证它写得对不对。
最后提醒一个时间上的变化:Let's Encrypt 已经在推进更短的有效期,六天的短周期证书已经可以通过 shortlived 配置申请,按规划到 2028 年 2 月默认有效期会降到 45 天。这意味着自动续期从可选项变成必选项,任何依赖手工续期的站点都会被淘汰。现在把监控和自动化落地,后面就不用再操这份心。
相关阅读:证书问题是接入层故障的常客。《服务器故障排查总纲:按现象反查的五层定位法》把过期、链不完整、HTTPS 识别错乱归成一串,本篇管证书本身,总纲帮你把相邻故障一次看全。
A5创业网 版权所有