原来 Certbot 的自动更新默认使用的是 systemd 定时器。

大家好,我是Kita。
虽然标题听起来像轻小说,但这篇文章是关于Let's Encrypt的。

最近,我们运营的一个网站的SSL证书过期了。
作为一名基础设施工程师,这确实有点尴尬,但正因如此,我才意识到自己长期以来的一个误解。

我一直以为“ Let's Encrypt 自动续订 = cron”。然而,经过调查,我发现 AlmaLinux 9 + Certbot 3.x默认使用systemd 定时器而不是 cron。

此外,导致此次到期的原因既不是上述任何一种,而是完全不同的其他原因。

这次,我将以备忘录的形式总结我在实际事件响应过程中调查的内容以及我学到的东西。

先说结论(给那些时间紧迫的人)

  • AlmaLinux 9(EPEL 版本的 Certbot)的自动更新而不是由 cron 处理。certbot-renew.timer
  • 即使计时器正在运行,更新仍可能根据身份验证插件的设置而继续失败。
  • 如果证书过期,请按以下顺序检查: systemctl list-timersjournalctl -u certbot-renew.service
  • 应该使用部署钩子来自动化将更新反映到 Web 服务器的过程。

下面按实际运作顺序解释整个过程。

一天突然出现的问题

有一天,当我访问我们新推出的服务的网站时,浏览器中突然出现一个警告页面,提示SSL证书已过期。

这可糟了。

Let's Encrypt 证书的有效期仅为 90 天,因此自动续期是正常运行的先决条件。
反之,如果证书过期,则意味着流程中的某些环节未实现自动化。

我的第一反应是:“等等,我不是设置了 cron 任务吗?”
于是我立即检查了大家最常用的 cron 任务。

$ sudo crontab -l $ sudo cat /etc/crontab $ sudo ls /etc/cron.d/

嗯,这里什么都没写。

我一开始想,“也许我漏掉了某个设置……”,但这说不通。
即使定时任务是空的,更新之前也一直都很成功

我进一步调查后,发现了这些信息。

最新版本的 Certbot 使用 systemd 定时器。

哦,真的吗?我还是第一次听说。

Certbot 的自动更新不一定是通过 cron 完成的。

这一点在官方文档中其实已经明确说明。 《Certbot 用户指南》的“自动续订”部分指出,大多数 Certbot 安装都预配置了自动更新,您可以通过查看crontab( /etc/crontab/etc/cron.*/* )或 systemd 定时器( systemctl list-timers )来检查这一点。

“请在系统的 crontab(通常是 /etc/crontab 或 /etc/cron.*/*)
或 systemd 定时器

来源: Certbot 用户指南“自动续期”

换句话说,自动更新并非总是通过 cron 实现的;具体方法似乎取决于发行版和软件包。
在本例中,适用于 AlmaLinux 9 的 EPEL 版 Certbot 使用的是 systemd 定时器方法。

我们来检查一下systemd定时器。

$ sudo systemctl list-timers | grep certbot

以下是结果。

令人惊讶的是,certbot-renew.timer竟然在运行。

换句话说,自动更新从一开始就已配置好,无需编写任何一行 cron 代码

cron 和 systemd 定时器的区别

既然说到这儿,我们就简单总结一下两者的区别。
从操作角度来看,查看日志和状态的便捷性要好得多。

物品 cron systemd 定时器
检查执行日志 自行跟踪系统日志和其他日志。 Journalctl -u 一枪
下次执行时间 没有办法直接看到(我必须自己计算)。 您可以使用systemctl list-timers 查看它们。
服务器宕机期间执行失败 未执行并跳过。 Persistent=true ,则启动后将进行恢复。
AlmaLinux 9 中的 Certbot 未使用的 标准(certbot-renew.timer)

然而,这就引出了一个问题:自动续订功能一直正常,
为什么会过期呢?

为什么过期了?原因是身份验证方法的问题。

证书在计时器运行时过期,
这表明续订过程尝试过但反复失败。
我们来查看日志。

$ sudo journalctl -u certbot-renew.service --since "yesterday" | grep -i error Jul 01 11:12:29 ip-172-26-9-○○.ap-northeast-1.compute.internal certbot[355188]: 证书 www.server-camp.com 续订失败,错误信息:手动插件无法正常工作;您的现有配置可能存在问题。 Jul 01 11:12:29 ip-172-26-9-○○.ap-northeast-1.compute.internal certbot[355188]: 错误信息:PluginError('使用手动插件非交互方式时,必须使用 --manual-auth-hook 提供身份验证脚本。')

哦...

“手动插件无法正常工作”
“必须提供身份验证脚本”

问题原因已查明:手动插件的身份验证错误。自动续期功能本身正在运行,但证书续期过程失败。这与cron 任务是否运行无关,而是身份验证方法本身存在问题

为什么手动插件无法自动更新。

答案直接写在官方 Certbot 用户指南的“手册”部分的“使用手动插件进行续订”章节中。

使用--manual创建的证书不支持自动续期

来源: Certbot 用户指南“手册”

唯一的例外情况是,`--manual-auth-hook` 参数准备了身份验证钩子脚本
--manual` 是一种依赖人工干预的身份验证方法,例如添加 DNS 记录,因此如果没有通过钩子进行自动化操作,则无法通过无人值守的定时器进行更新。

还有一点需要注意。
官方用户指南的“证书续订”部分清楚地说明了续订期间插件的处理方式。

“除非您指定其他插件或选项,否则续期尝试将使用与最初颁发证书时相同的插件和选项
。”

来源: Certbot 用户指南“续订证书”

简而言之,过去手动获取的证书将继续无限期地手动续期
计时器每次定期运行时都会重复失败,然后90天后证书过期——事情就是这样。

解决方案:切换到 webroot 身份验证并执行更新测试。

一旦知道了原因,剩下的就是解决问题了。

为了紧急解决证书过期问题,我使用certbot certonly --webroot手动续订了证书,导致续订设置( /etc/letsencrypt/renewal/ <域名>.conf)被更新。该设置已重写,现在是authenticator = webroot

$ sudo cat /etc/letsencrypt/renewal/www.server-camp.com.conf | grep authenticator authenticator = webroot

Webroot 身份验证是一种使用 HTTP-01 质询的身份验证方法,无需人工干预。
换句话说,一种允许定时器自动更新的身份验证方法

设置修正后,务必使用 `--dry-run` 参数运行更新测试。`
--dry-run` 的具体说明在官方命令参考文档中描述如下:

“对 Let's Encrypt 测试服务器执行测试运行
,获取测试(无效)证书,但不将其保存到磁盘。

来源: certbot 命令参考“--dry-run”

换句话说,你可以在不消耗实际速率限制的情况下检查更新路径。

$ sudo certbot renew --dry-run 正在将调试日志保存到 /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 正在处理 /etc/letsencrypt/renewal/www.server-camp.com.conf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 正在模拟 www.server-camp.com 现有证书的续期 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 恭喜,模拟所有续期均成功:/etc/letsencrypt/live/www.server-camp.com/fullchain.pem (成功) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
恭喜,所有模拟续订均已成功”表明续订过程已成功完成。接下来,我将检查服务状态。
$ sudo systemctl status certbot-renew.service ○ certbot-renew.service - 此服务自动续订找到的任何 certbot 证书 Loaded: loaded (/usr/lib/systemd/system/certbot-renew.service; static) Active: inactive (dead) since Mon 2026-07-06 07:16:35 JST; 4小时10分钟前 触发者:● certbot-renew.timer 进程:392173 ExecStart=/usr/bin/certbot renew --noninteractive --no-random-sleep-on-renew $PRE_HOOK $POST_HOOK $RENEW_HOOK $DEPLOY_HOOK $CERTBOT_ARGS (code=exited, status=0/SUCCESS) 主进程ID:392173 (code=exited, status=0/SUCCESS) CPU:333毫秒

最近一次执行已确认成功完成,状态码为 0/SUCCESS 。 *虽然显示“活动:非活动(已停止)” ,但此服务仅在执行更新检查时运行,因此在服务未运行时显示此信息属于正常现象。如“触发方式:certbot-renew.timer”所示,也可以确认此服务是由定时器启动的。

现在,自动更新应该可以正常工作了。
但是,实际上还存在一个潜在的隐患。

变更后自动部署 Apache 更新(部署钩子)。

这一点很容易被忽略,但即使证书文件已更新,
Apache 也不会自动加载新证书,因此需要重新加载或重启。

即使修复了自动更新问题,如果手动重新加载,仍然存在缺陷。
这也可以通过 Certbot 的系统实现自动化。

根据官方用户指南“证书续订”部分,/etc/letsencrypt/renewal-hooks/ 下的
predeploypost 将分别作为 pre、deploy 和 post hooks 自动执行。(如果有多个 hooks,它们将按文件名字母顺序执行。)

执行时间
尝试更新之前(即使失败也要执行)
部署 仅当更新成功时
邮政 更新尝试之后(即使失败)

Web 服务器只需在“更新成功”时重新加载,因此使用部署钩子是合适的。
官方文档也对此有所说明。

“如果您希望钩子仅在续订成功后运行
,请使用 --deploy-hook。”

来源: Certbot 用户指南“续订证书”

只需两步。首先,创建一个脚本。

$ sudo vi /etc/letsencrypt/renewal-hooks/deploy/reload-httpd.sh

里面就只有这些。

#!/bin/bash systemctl reload httpd

我还会授予执行权限。

$ sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-httpd.sh

由此,

证书续期(成功后)↓ 执行部署钩子 ↓ Apache 重新加载 ↓ 新证书立即生效

此过程可以完全自动化。此外,您可以使用 openssl 命令在更改生效后验证证书是否已正确应用。具体方法请参见“使用 openssl 命令验证证书完整性和验证结果”部分

这次我学到了:当物品临近到期日时,应该按什么顺序检查。

我这次学到的最宝贵的一课是:

在于“没有 cron 设置 = 没有自动更新”并不正确,
“定时器正在运行 = 更新正在工作”也不正确。

如果遇到过期的 Let's Encrypt 证书,建议按以下顺序检查。

  1. 计时器在运行吗?
    $ sudo systemctl status certbot-renew.timer
  2. 检查更新过程是否失败(原因通常在此处找到)。
    $ sudo journalctl -u certbot-renew.service
  3. 这种身份验证方法是否可以自动更新?
    $ sudo cat /etc/letsencrypt/renewal/<域名>.conf
  4. 校正后的测试
    $ sudo certbot renew --dry-run

如果你了解这个流程,像这样的调查可能只需要15分钟左右。

常见问题解答 (FAQ)

问:Certbot 的自动更新是使用 cron 还是 systemd 定时器运行?

A. 这取决于软件包和发行版。Certbot 官方用户指南的“自动续期”部分指出,大多数安装都预配置了自动更新,并列出了crontab 或 systemd 定时器( systemctl list-timers )作为检查方法。AlmaLinux 9(EPEL 版本)默认使用 systemd 定时器( certbot-renew.timer )。

问:为什么我的证书即使 certbot-renew.timer 正在运行也会过期?

A. 定时器仅保证定期执行更新命令,并不保证更新过程成功。
使用手动插件获取的证书如果没有身份验证钩子就无法自动续期,因此即使尝试执行,也会持续失败。请`journalctl -u certbot-renew.service` 查看错误详情

问:如何解决“手动插件无法正常工作”的错误?

A. 将证书获取方式切换为自动续期方式,例如 webroot 身份验证。`certbotcertonly --webroot -w 重新下载后,续订设置也会更新,之后自动更新功能即可正常工作。

问:为什么我续订证书后,浏览器仍然显示旧证书?

A. 这是因为 Web 服务器仍在使用启动时加载的旧证书。`/etc/letsencrypt/renewal-hooks/deploy/` 目录 ,则续期成功后,续期将自动应用于 Web 服务器。

问:可以同时配置 cron 和 systemd 定时器吗?

A. 我不建议这样做。
certbot renew 本身只会续订即将过期的证书,因此运行两次实际上危害很小,但有两个执行源意味着日志分散在不同的位置,这会使故障排除更加复杂。
最好坚持使用发行版的标准方法。

问:certbot.timer 和 certbot-renew.timer 有什么区别?

A. 内容相同,都是 Certbot 自动续期 systemd 定时器;只是名称因软件包而异。基于 RHEL 的系统,例如 AlmaLinux 9(EPEL 版本),使用certbot-renew.timer ;Debian/Ubuntu(apt 版本)使用certbot.timer ;而 snap 版本使用snap.certbot.renew.timer 。您可以使用`systemctl list-timers | grep certbot`命令在任何环境中进行检查。

概括

以下是我们从这次经历中学到的经验总结。

  • 在 AlmaLinux 9 中,Certbot 的自动续期certbot-renew.timer处理
  • 在某些情况下,即使不编写 cron 脚本,也可能发生自动更新(官方文档中也明确说明了这一点)。
  • 即使启用了自动更新,由于手动插件中的身份验证错误等原因,更新仍可能继续失败。
  • 找出原因的最短方法是 运行 `journalctl -u certbot-renew.service`。
  • 更新后,为了获得更好的性能,最好使用部署钩子自动重新加载 Web 服务器。

这次事件着实令人提心吊胆,但也让我深刻体会到,仅仅依赖 cron 任务可能会导致误诊。
希望这对其他管理 Let's Encrypt 的人有所帮助。

那好~

参考资料(官方文档和用户指南)

如果您觉得这篇文章对您有帮助,请点个“赞”!
2
加载中...
2票,平均分:1.00/12
9
X Facebook Hatena书签 口袋

这篇文章的作者

关于作者

我之前在Beyond公司做兼职,后来被正式聘用。我现在
人力资源部培训科的基础设施工程师。
我讨厌飞虫。