很多人用 Certbot 给服务器配过免费的 Let’s Encrypt HTTPS 证书,但两个月后往往发现网站还是红屏证书过期了。一查才发现,要么是系统里根本没配置自动续期的定时器,要么是证书虽然更新到了磁盘,但 Nginx 没有收到 reload 指令,依然在内存里跑着旧证书。
真正的自动续期必须做到两点:系统定期自动执行 certbot renew 探测,以及新证书落地时自动触发 Nginx 热重载。
这篇笔记记录如何用官方 Certbot 配置自动续期、挂载 Deploy Hook 钩子、确认 systemd timer 状态,以及用 Dry Run 提前演练。
为什么证书更新了网站依然显示过期
现在全世界主流的免费证书机构是 Let’s Encrypt。为了互联网安全,它强制规定:所有免费证书有效期只有 90 天!
很多新手最绝望的现场是:
“我明明网上搜教程安装了 Certbot,为什么过了 3 个月网站还是红标过期了?!”
【90% 小白证书猝死的四大真实绝望现场】
1. 磁盘更新了,但 Nginx 还在睡大觉:
Certbot 确实悄悄把新证书下载到了硬盘里,但没有通知 Nginx!
Nginx 内存里抓着的还是 3 个月前的那份旧证书,浏览器访问当场红标报警。
2. 误用 Standalone 模式导致“神仙打架”:
用了需要独占 80 端口的模式,结果后台自动续期时,80 端口正被 Nginx 占着,
Certbot 抢不到端口只能静默报错退出,拖到第 90 天直接暴毙。
3. “半边瘫”证书(手机打不开,电脑却正常):
配置证书时只写了 cert.pem,没写 fullchain.pem,漏掉了中间证书,
电脑浏览器缓存了根证书能看,安卓手机打开直接报“不受信任的危险网站”。
4. 盲目等待 90 天,从不演练:
以为敲完命令就万事大吉,从不用模拟演练命令检测,等收到报警邮件为时已晚。
今天我们就用一套标准的 SRE 级保姆化方案,彻底终结这四大噩梦。
前置准备工作
- [ ] 一台 Linux 云服务器(VPS):拥有 root 登录权限;
- [ ] Nginx 已处于运行状态:终端执行
systemctl is-active nginx返回active; - [ ] 域名解析已生效:你的域名(如
blog.example.com)必须真实解析到当前服务器的公网 IP; - [ ] 云厂商安全组放行 80 端口:Let’s Encrypt 签发证书必须通过
80/tcp进行所有权校验(HTTP-01 ACME Challenge)。
安装 Certbot 与 Nginx 插件
💻 【你本地的电脑】 打开终端连入服务器,进入 服务器端:。
官方推荐直接使用系统包管理器安装 certbot 以及对应的 python3-certbot-nginx 自动化插件:
# 1. 刷新仓库并安装 Certbot 及 Nginx 官方插件
export DEBIAN_FRONTEND=noninteractive
apt update && apt install -y certbot python3-certbot-nginx
# 2. 检查安装版本
certbot --version
- ✅ 成功标志:终端输出类似
certbot 2.x.x或certbot 3.x.x字样,没有任何报错。
申请证书与自动注入 Nginx 配置
传统教程最繁琐的一步,就是让新手自己写一堆 SSL 指令。而 Certbot 的 Nginx 插件可以直接智能感知你的站点配置,全自动修改并注入 HTTPS!
服务器端: 先定义你的域名变量(将第 1 行换成你自己的真实域名):
MY_DOMAIN="blog.example.com"
接着,直接执行以下自动化签发指令:
certbot --nginx -d ${MY_DOMAIN} \
--non-interactive \
--agree-tos \
--register-unsafely-without-email \
--redirect
- 🗣️ 大白话参数拆解:
--nginx:使用 Nginx 插件,零宕机,不需要停止你的网页服务,边跑业务边发证;-d 你的域名:指定签发的域名;-
--redirect:贴心神级参数!自动帮你把所有的http://请求强制 301 重定向到https://,访客输入不带 s 也会自动跳转小绿锁! -
✅ 成功标志:终端屏幕输出一大串文字,并在最后明确打出:
text
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/blog.example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/blog.example.com/privkey.pem
Deploying certificate
Successfully deployed certificate for blog.example.com to /etc/nginx/sites-enabled/blog.example.com.conf
Congratulations! You have successfully enabled HTTPS!
配置 Deploy Hook:证书更新后自动重载 Nginx
这是解决“证书在磁盘更新了,但 Nginx 还在用旧证书”的终极秘密武器!
Certbot 官方支持部署钩子(Deploy Hook):每当且仅当证书真正完成续签更新时,自动触发一条命令重载 Nginx!
服务器端: 整段复制并执行以下命令(自包含防呆脚本写入):
# 1. 创建官方专用的部署钩子目录
mkdir -p /etc/letsencrypt/renewal-hooks/deploy
# 2. 写入 Nginx 优雅重载脚本
cat << 'EOF' > /etc/letsencrypt/renewal-hooks/deploy/01-reload-nginx.sh
#!/bin/bash
# 只要有任何证书成功续签,静默优雅热重载 Nginx
if nginx -t >/dev/null 2>&1; then
systemctl reload nginx
echo "[$(date)] Certbot 证书已成功更新,Nginx 内存已优雅重载!" >> /var/log/certbot-reload.log
fi
EOF
# 3. 赋予可执行权限
chmod +x /etc/letsencrypt/renewal-hooks/deploy/01-reload-nginx.sh
# 4. 验证脚本落地情况
ls -la /etc/letsencrypt/renewal-hooks/deploy/01-reload-nginx.sh
- ✅ 成功标志:终端显示该脚本权限为
-rwxr-xr-x,从此只要续期成功,系统就会自动在毫秒级通知 Nginx 刷新内存!
确认 Systemd Timer 定时任务运行状态
现代 Linux 系统(Debian 11+/Ubuntu 20.04+)安装 Certbot 后,会自动注册一个后台系统定时器(Systemd Timer),每天默默巡检两次,如果发现离 90 天到期还剩 30 天以内,就会悄悄自动开始续签。
服务器端: 查验自动巡检哨兵是否在岗:
systemctl list-timers | grep -E 'certbot|NEXT'
- ✅ 成功标志:输出中能看到
certbot.timer,并且右侧ACTIVATES显示正在倒计时下一次触发时间(通常是几小时后)。 - 💡 安心保障:不需要你在
crontab里手动去添乱七八糟的定时脚本,现代 Linux 原生自带守护!
使用 Dry Run 模拟续期演练
不要等 3 个月后看命!现在就让 Certbot 假装今天证书已经过期,跑一次全流程模拟测试!
服务器端: 粘贴执行演练命令:
certbot renew --dry-run
-
🗣️ 大白话:
--dry-run是演习模式,它会向 Let’s Encrypt 测试服务器发起真实的 HTTP-01 验证并测试我们的 Deploy Hook,但不会真正覆盖你的现役证书。 -
✅ 成功标志:稍等 10 秒钟,终端屏幕必须打出这行黄金字样:
“`text
** DRY RUN: simulating ‘certbot renew’ close to cert expiry
** (The test certificates below have not been saved.)
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/blog.example.com/fullchain.pem (success)
** DRY RUN SUCCEEDED **
“`
看到 DRY RUN SUCCEEDED 的这一秒,你就可以彻底放下一百个心去睡大觉了!你的自动续期链路 100% 毫无阻碍!🎉
查看当前机器全量证书状态
如果你一台机器上反代了 5 个、10 个域名,想一眼看清每张证书还有几天过期怎么办?
服务器端: 运行这个官方原生指令:
certbot certificates
- ✅ 成功标志:屏幕会清爽列出你机器上的所有证书名字、存放路径、绑定的所有子域名,以及最重要的剩余有效天数(Expiry Date / VALID: 89 days)!
常见踩坑与排障笔记
| 异常现象 | 真实根因 | 对应一秒救命招式 |
|---|---|---|
| 电脑打开有绿锁,安卓手机打开却报“证书危险” | 证书链配置残缺(只配了 cert.pem) |
在 Nginx 配置里把 ssl_certificate 的路径换成 fullchain.pem(完整证书链包含中间机构证书),电脑手机全端秒解! |
执行申请或 renew 报 Failed to bind to :80 |
错用了 --standalone 模式,80 端口正被 Nginx 抢占 |
永远改用 --nginx 模式;或者临时改用 webroot 验证,不要强行杀掉 Nginx。 |
ACME 验证超时,提示 Invalid response from ... 404 |
外部流量走到了错误目录,或安全组未放行 80 | 1. 确保云平台安全组已放行 80 端口; 2. 如果开了 Cloudflare,去控制台确认该二级域名的 A 记录是否已经就位。 |
Cloudflare 开启后,浏览器报 Error 521 / 522 或重定向循环 |
Cloudflare SSL 模式与源站协议冲突 | 登录 Cloudflare 仪表盘,将「SSL/TLS」加密模式从 Flexible 切为 「Full (完全)」 即可瞬间秒开。 |
测试太频繁,被官方拉黑报 Too Many Requests |
触发了 Let’s Encrypt 单周 5 次相同证书上限 | 官方限制极其严格,反复测试时务必带上 --dry-run!万一真被限流,加一个前缀(如换成别的子域名)即可绕过限制。 |
还没有人在这篇手记留下纸条,来做第一个亮灯的人吧。