西西软件园多重安全检测下载网站、值得信赖的软件下载站!
软件
软件
文章
搜索

首页 → 业内动态 → 业内资讯 → ACME续期原理:为什么cron跑完了证书还是过期

ACME续期原理:为什么cron跑完了证书还是过期

相关软件相关文章发表评论 来源:本站整理时间:2026/11/3 1:59:49字体大小:A-A+

作者:xiix点击:2次评论:0次标签: SSL证书续期 ACME协议 certbot LetsEncrypt Nginx证书

Nginxv1.27.1 官方稳定版
  • 类型:服务器区大小:1.7M语言:英文 评分:5.0
  • 标签:
立即下载

上个月底有几个站友在群里问同一个问题:我的证书是开过自动续期的,怎么今天访问自己的站点突然变成502了,浏览器报「ERR_CERT_DATE_INVALID」。这种情况十有八九不是站点被打了,而是证书到点过期,而自动续期这条链路在某个环节早就断了,只是平时没人去查,直到过期那天才暴露出来。

如果你手上的服务器也是一台机器扛着几个站、证书全靠脚本续着,可以先看看这两家的机器再做规划:RackNerd(全球VPS,特价常推)、狗云DOGYUN(高性价比云服务器,多机房可选),挑一台带宽和线路都够用的做主站,剩下的挂到后面做备用,比所有业务都压在一台机器上要踏实得多。

SSL证书与服务器机房

服务器终端上的证书续期与定时任务流程

一、ACME到底在做什么:把「发证」拆成两个角色

要理解续期为什么失败,先得知道 ACME 这套协议是怎么跑起来的。Let's Encrypt 这类免费证书机构走的都是 ACME 协议,全称是 Automatic Certificate Management Environment,翻译过来就是「自动证书管理环境」。它把发证这件事拆成了两个角色:

一个是 ACME 客户端,也就是你服务器上装的 certbot、acme.sh 或者lego 这些命令行工具;另一个是 CA 服务器,也就是给你发证书的那个机构。

流程大致是这样:客户端先向 CA 注册一个账号(用邮箱),然后发起一次「订单」,说明我要申请一个 www.example.com 的证书;CA 收到订单后不会直接发证,而是要验证「你真的控制这个域名」。验证通过后,CA 才把私钥和证书链返回给你。整个过程走的是 HTTPS 接口,每一次交互都有签名证明「请求确实来自这个账号」,所以不需要把你的 DNS 服务商密钥交出去,也不需要你手工去点确认。

关键在于:验证环节会写一个「挑战」(challenge),客户端必须按要求在域名上摆出指定内容,CA 那边来读。HTTP-01 是让你在 80 端口的 /.well-known/acme-challenge/ 路径下放一个文件;DNS-01 是让你在 DNS 里加一条 TXT 记录。前者简单直接,后者能泛域名、能给内网或走 CDN 的站用,代价是需要能动 DNS。

两种验证路径对应的不同网络链路

二、为什么「cron 跑了」证书还是过期

这里是最容易误导人的地方。很多人加了定时任务,看日志里 certbot 也确实输出了「Congratulations! Your certificate has been saved」,就认为万事大吉。但续期链条上至少有三个环节,任何一环断了,页面上的证书纹丝不动。

第一环:定时任务真的被调度了。 在 Linux 上 cron 是有服务名的(cronie / crond),容器环境里更常见的是根本没起 cron 或者没挂载 crontab 文件。你在终端手动跑一遍当然成功,但那个「每天两点跑」的定时任务可能压根没被触发。验证办法很直接:去系统日志里翻 cron 的执行记录,或者在脚本第一行写一行时间戳,跑到日志文件里看看今天有没有新行。另外注意 crontab 里的 % 需要写成百分号加反斜杠,命令里带百分号又不转义,整条任务会直接报错。

第二环:验证环节通不通。 也就是上面说的 HTTP-01 或 DNS-01 是否成功。用 certbot renew --dry-run 可以跑一遍完整的流程而不消耗额度,它是排查续期问题最该先敲的命令。HTTP-01 常见的坑是:80 端口被防火墙拦了、服务器上有个反代把 /.well-known/ 路径劫持走了、Nginx 没监 80、或者域名已经套了 CDN 回源到内网导致 CA 读不到。DNS-01 常见的坑是 DNS 服务商的 API 密钥过期、脚本没装对应 provider 的插件、或者 TXT 记录还没生效就发起了验证。

第三环:续期完成之后,新证书有没有被服务加载。 这是最隐蔽的一段。certbot 续期成功后通常会在 Debian 系上装一个 systemd timer,在 CentOS 系上装 cron 任务,脚本里一般带 --deploy-hook 或者 certbot renew && systemctl reload nginx。但如果这个 hook 没写、或者写的是 reload 而 Nginx 编译成了别的名字、或者 systemd 的 timer 服务名写错、或者 reload 时报错但没人看,新证书就只是躺在 /etc/letsencrypt/live/ 目录里,Nginx 内存里跑的还是旧的那张。查证方式很朴素:openssl x509 -in /etc/letsencrypt/live/你的域名/fullchain.pem -noout -enddate 看文件里的到期日,再 echo | openssl s_client -connect 你的域名:443 2>/dev/null | openssl x509 -noout -enddate 看线上服务吐出来的到期日,两个日期对不上,就是没加载成功。

证书有效期与到期告警监控面板示意图

三、续期本身也不是每次都成功

另外一个容易被忽略的事实是:certbot 并不是无限续的。Let's Encrypt 的证书有效期是 90 天,acme.sh 默认走的是 60 天,续期成功的证书在 CA 侧还有「每张证书每周续期次数上限」这类风控限制。如果你的脚本写成了一分钟跑一次,或者每次跑都强制 --force-renewal,很容易在短时间内反复申请,把额度耗掉后直接拿不到新证书。所以正确的做法是交给定时任务低频执行,比如每天跑一次,certbot 自己会判断「还没到续期窗口」就什么都不做。

另外一个细节:certbot renew 只认已经登记在册的证书配置,它读的是 /etc/letsencrypt/renewal/ 目录下的配置文件。如果你当初是用 certonly 申请的证书、后来把配置文件删了或者容器重建导致丢失,renew 就找不到对应的条目,永远是「0 renewed, 0 total」,看起来一切正常,其实什么都没做。

四、我的排查顺序,你可以照着走一遍

结合上面的链路,我现在碰到证书问题基本是按这个顺序查的:

第一步,certbot certificates 看 CA 侧记录的到期日,这是「应该」什么时候过期;第二步,openssl s_client 看线上实际吐出来的到期日,这是「实际」什么时候过期,两个一对就知道是续期没跑还是加载没生效;第三步,certbot renew --dry-run 跑一遍,把验证环节的错误抓出来;第四步,去翻 cron 或 systemd timer 的日志,确认调度器到底有没有执行;第五步,加一条监控,别等证书过期了才知道。

最后那一步其实是最值的。证书有效期是可以被监控的,把它接进你现有的告警体系,剩余天数低于 20 天就发一条通知,比任何排查都省事。顺带一提,监控本身也要留个心眼:服务器时间如果不同步,脚本判断「距离到期还有多久」就会算错,这一环我在另一篇讲时钟同步的文章里详细写过。

工程师在工位上检查运行中的服务器

五、写在最后

证书自动续期这件事,配置的时候只要五分钟,但坏掉的时候通常是在没人值班的那个凌晨。真正让人安心的不是把 certbot 装上,而是把「定时任务触发、验证通过、证书加载、生效确认」这四个点都验证过一遍,并且给它配上一条到期提醒。

如果你也在用 certbot 或者 acme.sh,欢迎在评论区说说你的续期方式是什么,我是按 Debian 系 + Nginx 的组合在跑,CentOS 系的 systemd timer 那套以后再单独写一篇。

    相关评论

    阅读本文后您有什么感想? 已有人给出评价!

    • 8 喜欢喜欢
    • 3 顶顶
    • 1 难过难过
    • 5 囧囧
    • 3 围观围观
    • 2 无聊无聊

    发表评论

    昵称:
    表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲