入门指南

续期从不报错:四个时限、三种验证,与一份不依赖邮件的证书巡检

Let’s Encrypt 已停止到期提醒邮件。能不能续上,取决于触发方式、验证端口与失败限额三件独立的事。把四个时限拆开,给一份十分钟巡检与上线验收单。

续期是四条独立链路,任何一条断了都不会报警。

作者
AOPC 编辑部
发布
AOPC 编辑部
发布时间
更新
2026/10/29
核查
已复核
一个人在白板前把「证书怎么又过期了」拆成四个时钟:有效期、续期触发、验证端口与失败限额
经营者责任与 AI 执行层的关系

先看答案

适合谁
  • 把证书交给「自动续期」之后就没再看过的独立开发者
  • 站点在 Cloudflare 后面、源站 80 端口被封却不自知的人
  • 续期脚本日志全绿,浏览器却弹出证书过期警告的人
你会获得
续期是四条独立链路,任何一条断了都不会报警。
发布时间
实质更新
发布
AOPC 编辑部

60 秒结论

一分钟看懂这篇文章

续期是四条独立链路,任何一条断了都不会报警。

人负责

  • 决定巡检频率
  • 判断该不该换验证方式

AI 负责

  • 核对线上证书指纹
  • 比对磁盘与部署产物
  1. 拆分
  2. 探活
  3. 比对
  4. 留证

直接答案

「证书不是自动续期吗,怎么还会过期?」这个问题里有四条互相独立的链路。任何一条断了,都不会有人给你发消息:

时钟 它回答的问题 断了之后的样子
① 有效期 这张证书什么时候到期? 到期当天整站报错,之前一切正常
② 续期触发 谁在什么时候去申请新证书? 定时任务早就不再运行,没人发现
③ 验证可达 CA 能不能访问到你的验证路径? 站点 443 正常,验证却一直失败
④ 失败限额 失败太多次之后还能不能申请? 越重试越糟,最后连手工签都被暂停

最常见的错误是把四条合成一条:「我配了自动续期」=「证书不会过期」。而在 2026 年,连最后一道人工兜底——到期提醒邮件——在 Let’s Encrypt 这里也已经没有了。

本文只讨论 ACME 体系(Let’s Encrypt 是其中最大的一个 CA)的公开行为,不推荐具体客户端品牌,也不假设你的证书一定是 90 天。

一、兜底的那封邮件已经没有了

Let’s Encrypt 的到期提醒页面,现在整页只剩一条公告:

Expiration Email Service Shut Down

Let’s Encrypt has ended its email expiration service.

页面标注的 Last updated 是 June 25, 2025。也就是说,从 2025 年起,「等一封还有 20 天到期」的邮件再处理」这条路径不再存在。

这条要限定范围:这是 Let’s Encrypt 的行为,不代表其它 CA 也停了邮件;反过来,即使你的 CA 还发邮件,收件人邮箱是不是你常用的那个、会不会进垃圾箱,也不由你控制。把「邮件提醒」当成监控,本来就是借别人的管道做自己的告警。

二、续期触发:三代做法,与一个反直觉的 Retry-After

RFC 9773 在开头把 ACME 客户端决定「什么时候续期」的做法归成三类:

  1. they may be configured to renew at a specific interval (e.g., via cron),
  2. they may parse the issued certificate to determine its expiration date and renew a specific amount of time before then, or
  3. they may parse the issued certificate and renew when some percentage of its validity period has passed.

它同时点出前两类的结构性问题:CA 一旦改变证书寿命(缩短或延长),写死间隔或写死「提前 N 天」的客户端就会失效或过早续期,而且大量客户端会在同一时刻涌上来。

ARI(ACME Renewal Information)就是为这件事设计的。 它的关键不是「又一个接口」,而是把「什么时候续」从客户端猜,改成 CA 建议:

机制 原文口径 运维含义
suggestedWindow 含 start 与 end 的时间窗,CA 建议在这段内续期 不是「第 60 天」,是一段区间
取点方式 建议在窗口内均匀随机选一个时间;若已过去则立即续 同一批域名不会同时打过去
replaces 字段 新订单里带上它要替换的那张证书的标识 让 CA 认出「这是续期」而非新签
Retry-After 在 ARI 里表示期望的最小与最大等待时间;其它 HTTP 场景里它通常只是最小等待 不能用通用 HTTP 客户端的语义去理解
过期之后 客户端 MUST NOT 再查这张证书的 RenewalInfo 过期后再查没有意义,也救不回来
长期错误 下一次查询应在 6 小时后(或本地配置的默认值) 不是每秒重试

Let’s Encrypt 自己的接入指南给了两条可以照抄的节奏:

We recommend checking ACME Renewal Information for each certificate at least twice a day. The ARI endpoint will recommend when to renew.

As a backstop to ARI, we recommend renewing certificates automatically when they have a third of their total lifetime left. For certificates with a validity period under 10 days, we recommend renewing halfway through their total lifetime. For Let’s Encrypt’s current 90-day certificates, that means renewing 30 days before expiration.

拆成两层看:

  • 主路径是 ARI:一天至少查两次,按它给的窗口续。
  • 兜底是寿命比例:剩下三分之一时就该续;寿命不足 10 天的证书,用一半寿命作为节点。对 Let’s Encrypt 当前的 90 天证书,这个兜底点就是到期前 30 天。

「一天至少两次」不是随口给的数字:ARI 的窗口可能因为 CA 侧的原因(例如计划中的大规模吊销)提前,只查一次就会错过。这也是本文建议把「检查 ARI」放进每日任务、而不是每月任务的原因(编辑判断:具体次数按你的客户端能力定,两次是官方下限建议)。

同一个页面还有一条容易被忽略的运维建议:如果你的软件会装一个周期性批处理任务,请让它在一天里随机的那一秒运行,而不是固定整点——理由与本文无关但同源:整点的流量尖峰要由 CA 按峰值扩容。

续期失败不该被当成致命错误

同一份接入指南对失败重试给了具体节奏:

You should implement graceful retry logic in your issuing services using an exponential backoff pattern, maxing out at once per day per certificate. For instance, a reasonable backoff schedule would be: 1st retry after one minute, 2nd retry after ten minutes, 3rd retry after 100 minutes, 4th and subsequent retries after one day.

这里有一个方向性提醒:重试要退避,不能加速。 原因在下一节的限额里——失败次数本身是被计数的,越快重试,越快把配额打满。

三、三种验证方式:失败面完全不同

证书能不能签下来,取决于 CA 能不能验证「你控制这个域名」。三种方式做的事一样,失败的条件完全不一样:

HTTP-01 DNS-01 TLS-ALPN-01
验证位置 http://<域名>/.well-known/acme-challenge/<TOKEN> _acme-challenge.<域名> 的 TXT 记录 443 端口上的 TLS 握手(自定义 ALPN)
端口 只能 80 不涉及 443
通配符 不能 可以 不能
验证 IP 可以 不可以 可以
自动化前提 80 端口可达、多台服务器返回同一文件 DNS 服务商有 API、能确认传播 客户端支持(原文:支持有限)
典型失败 ISP 封 80、WAF 挡住挑战路径、多机不一致 API 凭据风险、无 API、传播时间不明 反向代理不认这个 ALPN

几条原文细节值得抄进排错清单:

  • HTTP-01 只走 80 端口:「The HTTP-01 challenge can only be done on port 80. Allowing clients to specify arbitrary ports would make the challenge less secure, and so it is not allowed by the ACME standard.」
  • 它跟随重定向,但最多 10 跳,且只接受 http:/https:、只接受 80/443 端口;跳到 HTTPS 时不校验证书(因为它本来就是在 bootstrap 证书,路上可能遇到自签名或过期证书)。
  • 它可能从多个 vantage point 多次抓取,所以「我本机 curl 得到」不等于「CA 抓得到」。
  • 多台服务器必须都能返回同一个文件,否则请求落到哪台就成哪台。
  • DNS-01 的代价是凭据:原文把「Keeping API credentials on your web server is risky」列为 cons 第一条;另有「DNS API 可能不提供传播时间信息」。
  • TLS-ALPN-01 不适合大多数人:原文是「This challenge is not suitable for most people. It is best suited to authors of TLS-terminating reverse proxies…」,且客户端支持有限。

这里有一个很常见的错位:站点在 443 上跑得好好的,于是「网站在线」被当成「验证没问题」。但 HTTP-01 走的是 80。80 被封、被 WAF 拦、被重定向到登录页,首页都仍然是 200。 监控首页证明不了验证路径可达(编辑判断,但不是推测:两者是不同端口、不同路径、不同规则集)。

四、失败会自我放大:限额不是「签多少张」那么简单

Let’s Encrypt 的限额按令牌桶逐请求计算,可以突发用完,也可以摊开用。更关键的是三条:没有临时重置的办法;容量只会随时间慢慢回填;吊销证书不会重置限额(「Revoking certificates does not reset rate limits, because the resources used to issue those certificates have already been consumed.」)。

对一人公司最相关的有四组:

限额 数值 计数范围 回填速度
New Certificates per Registered Domain 50 张 / 7 天(IPv4 按单地址、IPv6 按 /64 视作注册域) 全局:不分账号,所有新订单都算 1 张 / 202 分钟
New Certificates per Exact Set of Identifiers 5 张 / 7 天(标识符集合完全相同) 全局 1 张 / 34 小时
Authorization Failures per Identifier per Account 5 次 / 小时 单账号、单标识符 1 次 / 12 分钟
Consecutive Authorization Failures per Identifier per Account 1,152 次连续失败后暂停 单账号、单标识符 1 次 / 天,成功验证即归零

第 2 行是排错时最容易踩的:原文把「反复重装客户端」「每次部署都删掉 ACME 配置」列为常见原因,并说明这个限额故意设得低,就是为了防止有 bug 的系统快速吃掉别人的容量。改配置重试三次,就可能已经用掉 5 张里的 3 张。

第 4 行更隐蔽:它不是「每小时」限额,而是连续失败累计。官方给了一张换算表(Failures per Day → Time to Pause),摘几行:

每天失败次数 触发暂停需要
1 永不暂停
2 1,152 天(约 3.16 年)
10 128 天
30 40 天
120 10 天

按 1,152 次总量与「每天回填 1 次」推算:每 5 分钟重试一次的脚本,一天 288 次失败,约 4 天就能把一个标识符打到暂停(这是按原文两个数字做的除法,非原文表述)。暂停之后每次申请都会返回一个指向自助门户的链接,可以在那里解封该标识符及账号下最多 49,999 个其它被暂停的标识符。

还有两类「看不见的」限额:

  • 每 IP 的端点请求限额(如 /acme/new-order 每秒 300 次、突发 200;/acme/new-nonce 每秒 20 次)。超限返回 503 并带 Retry-After。
  • 续期豁免不是全豁免:ARI 续期豁免所有限额;非 ARI 续期(标识符集合完全相同、忽略大小写与顺序)只豁免 New Orders per Account 与 New Certificates per Registered Domain,仍受 Authorization Failures per Identifier per Account 与 New Certificates per Exact Set of Identifiers 限制。换句话说,「我在续期」不等于「不会撞限额」。

测试与排错该去哪,原文给了明确指向:staging 环境的限额「significantly higher」,且不消耗生产配额。

五、要监控的四个信号

把四件事分开监控,比监控「续期脚本退出码」有用得多:

  1. 到期时间:从外部看线上实际提供的那张证书,而不是看磁盘上的文件。
  2. 续期是否真的发生:证书指纹/序列号变了没有。命令退出 0 只说明命令跑完了。
  3. 部署是否跟上:新证书签下来之后,Web 服务器/负载均衡/CDN 边缘有没有加载它。磁盘上是新的、握手拿到的是旧的,是常见组合。
  4. 验证路径是否可达:80 端口、.well-known 路径、DNS TXT 三个入口分别探活。

再加一条「额度」:把续期失败的次数与原因记进日志,别让一个每 5 分钟重试的循环悄悄把连续失败次数推到 1,152。

过期不是「点一下继续访问」

如果域名带 HSTS,证书错误的后果会更硬。接入指南的原话:

while people can usually click through a browser warning about a name mismatch or expired certificate, browsers do not allow such a click through for hostnames with an active HSTS header.

也就是说,对启用了 HSTS 的站点,证书过期约等于整站不可用,不存在「用户点一下继续」的缓冲。至于 HSTS 的 max-age 该设多长、要不要 preload,是另一个话题,本文不展开。

六、十分钟巡检

以下命令在 macOS/Linux 自带工具范围内,按顺序执行。它们的共同点是都从外部看结果,不依赖续期脚本自己的日志。

① 线上实际提供的那张证书

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -fingerprint -sha256

看三样:notAfter、签发者、SHA-256 指纹。把指纹抄下来,下次比对用。

② 还剩多少天(脚本友好)

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -checkend 2592000

-checkend 2592000 是 30 天(秒)。输出 Certificate will not expire 时退出码为 0,否则非 0——这一条就能直接接进任何告警系统。

③ 磁盘上的证书与线上是不是同一张

openssl x509 -in /path/to/cert.pem -noout -fingerprint -sha256 -dates

两条指纹不一致,说明「签下来了但没部署」,或者「部署到了另一台机器」。这是本文最推荐先查的一项。

④ 链上的每一张都要看

echo | openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null \
  | grep -E '^ *[0-9]+ s:|^ *i:'

s: 是站点证书,i: 是签发者。中间证书也会过期;「我的证书没过期」不等于「链是完整的」。

⑤ HTTP-01 的路径是否可达

curl -sS -o /dev/null -w '%{http_code}\n' http://example.com/.well-known/acme-challenge/probe-not-exist

期望是 404(路径可达、文件不存在),不是 403、302 到登录页或 Cloudflare 的挑战页。真实验证时 CA 要的是那个 token 文件返回 200;这里用不存在的文件名,只为确认「请求能到达你的服务器」。

⑥ DNS-01 的记录是否还在

dig +short TXT _acme-challenge.example.com

不是每次都要有记录(验证完通常可以删),但如果你的客户端依赖「长期保留的 CNAME 委派」,这条能确认委派没断。

⑦ ARI 有没有在跑

没有一条通用命令——ARI 的地址与证书标识由 CA 与客户端决定。能查的是客户端日志里有没有 renewalInfo 相关请求,以及它上次给出的窗口是什么时候。如果你的客户端根本不支持 ARI,就退回到「寿命三分之一」的兜底,并把这件事写进运维笔记,而不是假设它在工作。

七、上线验收单

# 检查项 怎么验 不通过的样子
1 到期提醒邮件已不作为唯一告警 问自己:邮件停了会怎样 没人知道证书哪天到期
2 有独立的到期探测(外部握手) 上面第 ② 条接进告警 只有续期脚本的日志
3 续期触发方式写下来了 文档里能查到是 ARI 还是固定间隔 换台机器就不知道原来怎么配的
4 有「寿命三分之一」的兜底 配置里能找到这个阈值 ARI 一失效就永久不续
5 重试是退避的,不是每 5 分钟 看失败重试代码 失败越多、撞限额越快
6 测试走 staging 配置里能切换 排错时把生产配额打满
7 验证端口(80 或 443)从公网可达 外部探测,不用本机 curl 站点 443 正常、验证全失败
8 多台服务器返回同一验证内容 逐台请求同一路径 请求落到哪台全看运气
9 部署后比对指纹 第 ③ 条 磁盘新、线上旧
10 链证书也在检查范围内 第 ④ 条 叶子证书正常、中间证书过期
11 失败了有人知道 告警能到达人 日志里全是 error,没人看

八、五种常见误读

误读一:「自动续期配好了,就不会过期。」 「配好」只覆盖了第 ② 个时钟。验证路径、部署、限额任何一个变了,续期都会失败,而且失败通常不发出任何声音。

误读二:「续期命令退出 0,就是续上了。」 退出 0 只说明这个进程正常结束。要看指纹变没变、notAfter 有没有往后推。

误读三:「证书签下来了,网站就是新的了。」 签名与部署是两件事。反向代理、负载均衡、CDN 边缘都可能还拿着旧证书;磁盘上的文件更新不等于握手里的是它。

误读四:「HTTP-01 可以换个端口,也能签通配符。」 两件都不行。端口只能是 80,通配符只能走 DNS-01。

误读五:「续期不占限额。」 ARI 续期豁免所有限额;非 ARI 续期只豁免两条,仍受另外两条限制。而且失败次数本身就是一条独立的限额。

九、本周就能做的五件事

  1. 现在就跑一次第 ② 条,把「还剩多少天」变成一个数字。
  2. 把线上指纹与磁盘指纹各抄一份,对一下是不是同一张。
  3. 确认 80 端口从公网可达(哪怕你的站点全站 HTTPS)。不可达就把验证方式换成 DNS-01。
  4. 把重试逻辑改成退避:1 分钟、10 分钟、100 分钟,之后每天一次。
  5. 删掉「等邮件提醒」这个假设,在日历上留一个每月一次的巡检,或者把它接进现成的告警系统。

如果只能记住一件事:证书过期从来不是「续期那一步」失败,而是四条链路里最安静的那条先断了。


边界说明:本文关于 Let’s Encrypt 的陈述全部来自其四个公开文档页(2026-10-29 访问,均 HTTP 200:expiration-emails 25 466 B、rate-limits 44 071 B、challenge-types 34 029 B、integration-guide 40 181 B),ARI 的协议语义来自 RFC 9773(同日访问,HTTP 200,25 666 B,IETF Standards Track,2025-06)。不写「Let’s Encrypt 会发到期提醒」、「HTTP-01 支持任意端口/可签通配符」、「续期一定不撞限额」、「自动续期=不会过期」,也不写任何「续期成功率」「故障时长」数字。文中标注为编辑判断的三处:每日检查次数的具体取值、80 端口与站点可用性的错位、以及巡检项优先级排序。第六节的命令是通用工具用法,不是上述来源的原文;-checkend 的秒数按 30 天换算(30×24×3600),闰秒不影响该用途。第四节的「约 4 天」是按原文 1,152 次与每天 288 次做的除法,非官方表述;暂停换算表仅摘录四行,完整表以原文为准。本文不推荐任何 ACME 客户端或托管服务品牌。

来源

以下页面均于 2026-10-29 逐条访问并验证为 HTTP 200;字节数为当日抓取的实际大小。

  1. Expiration Emails · Let’s Encrypt核查于 2026/10/29(200,25 466 B;页面标注 Last updated June 25, 2025):整页只剩公告「Expiration Email Service Shut Down」与一句「Let’s Encrypt has ended its email expiration service.」。
  2. Rate Limits · Let’s Encrypt核查于 2026/10/29(200,44 071 B;Last updated August 5, 2026):限额按令牌桶逐请求计算;无临时重置手段、吊销不重置;New Registrations per IP 10 个 / 3 小时(回填 1 个 / 18 分钟)、per IPv6 /48 500 个 / 3 小时;New Orders per Account 300 个 / 3 小时(1 个 / 36 秒);New Certificates per Registered Domain 50 张 / 7 天、全局(IPv4 按单地址、IPv6 按 /64,回填 1 张 / 202 分钟);New Certificates per Exact Set of Identifiers 5 张 / 7 天、全局(回填 1 张 / 34 小时,不提供 override);Authorization Failures per Identifier per Account 5 次 / 小时(1 次 / 12 分钟);Consecutive Authorization Failures 1,152 次、回填 1 次 / 天、成功即归零,暂停后经自助门户解封(可含最多 49,999 个其它标识符),并附 Failures per Day → Time to Pause 换算表;端点级每 IP 限额(如 /acme/new-order 300/s、突发 200;/acme/new-nonce 20/s)超限返回 503 与 Retry-After;ARI 续期豁免所有限额,非 ARI 续期豁免 New Orders per Account 与 New Certificates per Registered Domain、仍受另外两条限制;排错建议改用 staging(限额显著更高)。
  3. Challenge Types · Let’s Encrypt核查于 2026/10/29(200,34 029 B;Last updated February 12, 2026):HTTP-01 文件位于 /.well-known/acme-challenge/<TOKEN>、CA 可能从多个 vantage point 多次抓取;重定向最多 10 跳、仅 http/https、仅 80/443、跳 HTTPS 时不校验证书;只能 80 端口、不能签通配符、多台服务器须返回同一文件、ISP 封 80 会失败、可验证 IP;DNS-01 用 _acme-challenge TXT、可签通配符、不能验证 IP,cons 含「API 凭据放在 Web 服务器上有风险」「服务商可能不提供 API」「可能不提供传播时间信息」;TLS-ALPN-01 走 443、RFC 8737、自定义 ALPN、「not suitable for most people」、客户端支持有限、多台服务器同样要一致、不能签通配符、可在 80 不可用时使用。
  4. Integration Guide · Let’s Encrypt核查于 2026/10/29(200,40 181 B):建议每张证书每天至少查两次 ARI;兜底为「剩余寿命三分之一」时续期,寿命不足 10 天的证书用一半寿命,对当前 90 天证书即到期前 30 天;失败应按指数退避、每张证书最多每天一次(示例 1 分钟 / 10 分钟 / 100 分钟 / 之后每天);周期任务应在一天中随机秒运行;启用 HSTS 时浏览器不允许对过期证书「点击继续」;建议前端优先从持久存储取证书,取不到再签发。
  5. RFC 9773: ACME Renewal Information (ARI) Extension核查于 2026/10/29(200,25 666 B;IETF Standards Track,2025-06):三种传统续期策略及其对 CA 调整寿命的阻碍;suggestedWindow 含 start/end,建议窗口内均匀随机取点、已过去则立即续;replaces 字段标识被替换的证书;ARI 的 Retry-After 表示期望的最小与最大等待(与一般 HTTP 语义不同);证书过期后或被视为已替换后客户端 MUST NOT 再查 RenewalInfo;长期错误后下一次查询应在 6 小时后(或本地默认值);服务端对 Retry-After 的取值考量(如预留 12 小时调查、6 小时拉取、6 小时续期)。

唯一主行动

把下一步变成可执行动作

进入发布、维护与回滚工作流