Let's Encrypt 证书自动续期:避免你的网站半夜掉线
结论先行:单域名证书只需安装 Certbot 并确保其自带的 systemd timer 处于
active状态,由守护进程每日两次错峰检测,在证书剩余 30 天时自动静默刷新;若是*.example.com泛域名证书,则必须采用 DNS-01 验证模式,配置 Cloudflare API Token 权限与python3-certbot-dns-cloudflare插件即可实现全自动无人值守续期。半夜突发掉线通常源于三大硬伤:Timer 未激活、续期后漏配post_hook重载 Web 进程、或 DNS Token 被意外撤销。
凌晨时分手机突发收到大量报警,海外访客打开主页看到全屏红字安全拦截,排查发现是 90 天前申请的 SSL 证书过期了。本指南为你构建一套稳固的自动化续签机制,告别证书过期的噩梦。
0、写在前面
HTTPS 是出海独立开发项目的生命线。现代浏览器对明文 HTTP 站点全面标记为不安全,搜索引擎也会对未加密站点降低权重。
Let’s Encrypt 免费提供了权威可信的 TLS 证书,但其证书有效期严格限制在 90 天。这并非故意增加运维复杂度,实则是严密的安全考量:
- 短生命周期可将私钥意外泄露造成的潜在威胁窗口收敛至极小范围;
- 倒逼工程团队彻底告别人工手动更换,建立健壮的自动化轮换链路;
- 随着 CA/Browser 论坛逐步推进更短周期的证书标准,自动化续签已成为生产环境的底层刚需。
本文带你从单域名 HTTP-01 验证、泛域名 DNS-01 验证,到服务自动平滑重载与状态监控,彻底攻克证书续期卡点。
1、期望目标
阅读并实操本篇指南后,你将达成以下目标:
- [ ] 彻底掌握 Let’s Encrypt 90 天生命周期机制与 30 天自动刷新窗口;
- [ ] 启用并验证 Certbot 原生 systemd timer 自动化定时任务;
- [ ] 配置 Cloudflare API Token 最小权限,实现
*.domain.com泛域名证书自动无人值守续期; - [ ] 掌握
deploy_hook与post_hook触发器,确保新证书落地后 Nginx 自动毫秒级平滑重载; - [ ] 掌握
certbot renew --dry-run沙盒仿真演练技巧; - [ ] 熟练排查防火墙拦截、Token 失效、频率限制(Rate Limits)与证书链缺失故障。
2、技术选型与架构设计
验证模式与证书类型选型
Let’s Encrypt 支持两种核心挑战验证模式(ACME Challenge):
| 验证模式 | 适用证书类别 | 核心机制 | 优势 | 潜在卡点 |
|---|---|---|---|---|
| HTTP-01 验证 | 单域名、常规多域名 (SAN) | CA 节点请求 /.well-known/acme-challenge/<TOKEN> |
配置极简,仅需 80 端口可达 | 无法签发泛域名;受 CDN 缓存干扰 |
| DNS-01 验证 | 泛域名 (*.domain.com)、内网域名 |
CA 节点查询 _acme-challenge.domain.com TXT 记录 |
不依赖 80 端口;一张证书覆盖所有子域 | 需要 DNS 托管商支持 API 写入 |
自动轮询与续期状态流转机制
3、完整操作步骤与配置
3.1 环境就绪与当前证书健康度盘点
登录 VPS 后,首先清查服务器上的所有现存证书:
1 | # 查看所有已纳管的证书、对应域名及其剩余可用天数 |
输出中会明确标注每个证书的过期时间戳与存储路径:
1 | Certificate Name: example.com |
若尚未安装 Certbot,推荐安装官方维护的 Python3 现代版本:
1 | # Ubuntu/Debian |
3.2 方案 A:标准单域名 HTTP 自动续期(Systemd Timer 模式)
通过官方 APT 包安装的 Certbot 会在后台自动注册并启动 certbot.timer。
第一步:检查 Timer 是否在线
1 | # 检查 certbot timer 运行状态 |
若状态显示为 inactive,手动执行激活与自启:
1 | sudo systemctl enable --now certbot.timer |
查看系统配置,默认排程如下:
1 | [Timer] |
00,12:00:00:每日固定执行两次;RandomizedDelaySec=43200:在此 12 小时区间内随机抖动,避免向 Let’s Encrypt 集中并发冲击;Persistent=true:如果服务器中间经历关机重启,开机后立即补跑检查。
第二步:配置证书续期后的平滑重载 Hook
很多开发者最容易踩的坑:证书明明续期成功了,但网页端依然报证书过期!
原因在于 Web 服务器(Nginx)将证书读入内存后,若不主动接收 reload 信号,内存中的老证书永远不会释放。
编辑该域名的续订专属参数文件:
1 | sudo nano /etc/letsencrypt/renewal/example.com.conf |
在 [renewalparams] 段末尾补上 post_hook 指令:
1 | [renewalparams] |
这样只有当证书真正发生了签发换新时,系统才会自动触发 Nginx 热重载,既安全又环保。
第三步:本地沙盒仿真验证(Dry-run)
配置完毕后,通过仿真命令验证全部校验链路:
1 | sudo certbot renew --dry-run |
当终端输出 Congratulations, all simulated renewals succeeded 时,代表标准证书的自动化续签流程全部配置成功。
3.3 方案 B:通配泛域名自动续签(Cloudflare DNS-01 实战)
对于多子域名项目,强烈推荐使用 *.domain.com 泛域名证书。
第一步:创建 Cloudflare API Token 最小权限凭据
为防止主账户 Global API Key 泄露带来全站劫持风险,必须创建最小权限 API Token:
- 登录 Cloudflare 控制台,进入 My Profile → API Tokens → 点击 Create Token;
- 选用 Create Custom Token;
- 权限设定:
Zone→DNS→Edit; - 作用域限制:
Zone Resources→Include→Specific zone→ 选中你的目标出海域名; - 点击 Continue to summary 并生成复制 Token 字符串。
第二步:安装 DNS 插件并存入安全凭证
1 | # 安装 Cloudflare 官方 ACME 适配插件 |
如果你希望对域名基线做自动化管理,可参考 ittinker-scripts 中的 cloudflare-domain-baseline 工具,统一规范 DNS 安全配置。
第三步:一键签发泛域名证书
1 | sudo certbot certonly \ |
Certbot 会自动通过 Cloudflare API 向你的域名注入 _acme-challenge 的 TXT 解析记录,Let’s Encrypt 全球节点查验成功后即刻下发证书,并在验证完毕后自动清除该临时 TXT 记录。
第四步:仿真演练泛域名续期
1 | sudo certbot renew --dry-run |
4、生产落地检查清单
部署上线前,对照下表逐一核实:
| 校验模块 | 检查命令 / 操作方法 | 合格验收标准 |
|---|---|---|
| Timer 激活 | systemctl is-active certbot.timer |
必须输出 active |
| 开机自启 | systemctl is-enabled certbot.timer |
必须输出 enabled |
| 仿真演练 | sudo certbot renew --dry-run |
所有被管理的证书均显示 succeeded |
| Token 权限 | stat -c "%a" /etc/letsencrypt/cloudflare.ini |
权限数字必须为 600 |
| 重载生效 | 检查 /etc/letsencrypt/renewal/*.conf |
明确包含 post_hook = systemctl reload nginx |
| 证书文件链 | 检查 Nginx 配置中的公钥路径 | 必须指向 fullchain.pem,严禁使用 cert.pem |
5、高频故障与异常排查
Q1:仿真测试报错 Failed to authorize?
- HTTP-01 模式失败:
80 端口无法被公网访问,或 Nginx 将/.well-known/acme-challenge/路径做了错误的 301 循环跳转。在 Nginx 中显式放行该目录:1
2
3
4location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/html;
} - DNS-01 模式失败:
检查 API Token 是否设置了 IP 白名单导致 VPS 外部 IP 被拦截;或 DNS 传播延迟较高,可在命令中追加参数--dns-cloudflare-propagation-seconds 60。
Q2:遭遇 Let’s Encrypt 频率限制(Rate Limits)怎么解?
Let’s Encrypt 对生产环境有严格的配额保护:
- 单主域名(Registered Domain)每周证书上限为 50 张;
- 完全相同的主机名集合每周限 5 张;
- 失败授权上限为单主机名每小时 5 次。
解法:在频繁调试脚本时,务必加上 --dry-run,或者在测试阶段指定 Staging 测试环境(签发不被系统信任的测试证书,不计入生产配额):
1 | sudo certbot certonly --dry-run --test-cert ... |
Q3:浏览器提示「不受信任的证书」或在部分 Android 机型上报错?
原因:Nginx 配置中误将 ssl_certificate 指向了 cert.pem(只有叶子证书),缺少中间 CA 证书链。
解法:将配置修改为完整证书链文件:
1 | ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; |
6、核心数据与行业参考
- Let’s Encrypt 日签发体量突破千万:作为由 ISRG 运营的公益性现代证书颁发机构,Let’s Encrypt 目前服务的全球活跃网站已超 7 亿,是保障全球 Web 安全传输的基础骨干。ISRG Annual Report
- 证书生命周期未来演进趋势:主流浏览器厂商与 CA/B 论坛正持续讨论将公有 CA 证书最大有效期进一步缩短至 45 天甚至更短。依靠手动申请和人工记录日历的做法将彻底被工业界淘汰,自动化运维是唯一可持续的路径。CA/Browser Forum Updates
- OCSP 机制退役:Let’s Encrypt 已于 2025 年正式停用实时在线 OCSP 响应器,全量转向证书吊销列表(CRL)模式。生产配置中即便关闭
ssl_stapling也不会影响现代浏览器的正常验证。Let’s Encrypt Changes
7、推荐工具与延伸阅读
- Nginx 配置速查实战:学习如何将自动续期的证书安全装配进 Nginx 生产环境。
- Cloudflare 基础配置与防封指南:构建域名解析与边缘高防体系。
- ittinker-scripts 开源自动化运维工具库:包含一键环境初始化与防火墙加固脚本。