ACME 客户端与自动化
SSL/TLS 证书自动续期配置指南
SSL 证书自动续期要三样东西:至少每天运行一次 ACME 客户端的定时任务,续期后让服务加载新证书的重载钩子,以及能发现失败的外部监控。覆盖截至 2026 年 11 月的 Certbot、acme.sh、lego、Caddy、Traefik、cert-manager 和 win-acme,以及宝塔等面板。
前提条件
先要知道证书都在哪里、各自由什么工具签发。
- 能登录所有处理 TLS 的服务器、代理、集群和面板。
- 你的全部域名清单;用 CT 证书查询 能看到为你的域名签发过的所有证书,容易找出被遗忘的那几张。
- 有权限修改这些系统上的 cron、systemd 定时器或计划任务。
第一步:盘点证书和客户端
每种 ACME 客户端都有列出证书的命令,先用它们查清有哪些证书、分别由谁续期:
sudo certbot certificates # Certbot
acme.sh --list # acme.sh
sudo lego certificates list --path /etc/lego # lego v5
kubectl get certificates -A # cert-manager
Caddy 和 Traefik 自己管理证书,看日志或存储文件;Windows 上 win-acme 用 wacs.exe --list 列出续期任务;宝塔、1Panel 在面板的 SSL/证书页面查看。不在任何列表里的证书就是手动安装的,需要重点处理。
第二步:确认定时任务至少每天运行
定时任务至少每天运行一次,各客户端的调度方式不同:
| 客户端 | 调度方式 | 检查方法 |
|---|---|---|
| Certbot(snap) | systemd 定时器,每天两次 | systemctl list-timers | grep certbot |
| Certbot(pip) | 需要自己加 cron | grep certbot /etc/crontab |
| acme.sh | 用户 crontab,3.1.4 起每 6 小时 | crontab -l | grep acme.sh |
| lego | 自己配置的 systemd 定时器或 cron | systemctl list-timers | grep lego |
| Caddy、Traefik | 内置在常驻进程里 | 服务日志 |
| cert-manager | 集群里的控制器 | kubectl get pods -n cert-manager |
| win-acme | Windows 计划任务 | 任务计划程序里的 win-acme 任务 |
| 宝塔、1Panel | 面板计划任务 | 面板“计划任务”页面 |
缺少调度就补上。pip 安装的 Certbot:
echo "0 0,12 * * * root /opt/certbot/bin/python -c 'import random; import time; time.sleep(random.random() * 3600)' && sudo certbot renew -q" | sudo tee -a /etc/crontab > /dev/null
第三步:让客户端自己决定何时续期
优先用 ARI 和按有效期计算的默认值,不要写死天数。Certbot 4.1 及以上在 certbot renew 时查询 ARI,否则在剩余三分之一有效期时续期;acme.sh 3.1.4 及以上默认启用 ARI;lego v5 默认使用 ARI(--ari-disable 关闭),--renew-days 为 0 时按有效期计算。没有特殊原因就删掉旧的覆盖设置,比如 Certbot 续期文件里的 renew_before_expiry = 30 days、acme.sh 写死的 --days 60:
sudo grep -H renew_before_expiry /etc/letsencrypt/renewal/*.conf
第四步:重载所有用到证书的服务
磁盘上的证书换了,服务不重载就不会生效。用客户端的钩子机制:
sudo certbot reconfigure --cert-name example.com --deploy-hook "systemctl reload nginx"
acme.sh --install-cert -d example.com --ecc --fullchain-file /etc/nginx/ssl/example.com.pem --key-file /etc/nginx/ssl/example.com.key --reloadcmd "systemctl reload nginx"
lego 用 --deploy-hook;Caddy、Traefik、cert-manager 会自动重载。详见 Certbot 续期钩子。
验证
续期流程正常时,测试环境演练能成功完成,下一次实际续期后线上证书的到期时间会往后推。用 --dry-run 或测试环境演练续期,不消耗生产环境的频率限制:
sudo certbot renew --dry-run
acme.sh 和 lego 用测试环境(--staging 或 --server https://acme-staging-v02.api.letsencrypt.org/directory)。再用 SSL 证书检查 或终端确认线上证书:
curl ssl.sh/example.com
域名多时用 批量 SSL 检查。
自动续期
第二到第四步做好后续期就是自动的,剩下的是发现失败。Let's Encrypt 2025 年 6 月 4 日起不再发到期提醒邮件,需要自己设置告警:ssl.sh 监控(开发中) 从外部检查线上证书并在到期前提醒,也能发现“续期成功但服务没重载”的情况。上面的调度方式已经能应对 Let's Encrypt 2027 年 2 月 10 日的 64 天、2028 年 2 月 16 日的 45 天默认有效期,以及证书有效期时间线上的行业上限。
常见问题排查
- 续期报 timeout during connect:首次签发后 80 端口有变化(新防火墙规则、套了 CDN、加了跳转、备案失效被拦截),见 certbot 连接超时。
- too many certificates already issued:脚本出错反复续期,见 Let's Encrypt 频率限制。按 ARI 续期可以避免这种情况。
- CAA record prevents issuance:首次签发后新加了 CAA 记录,见 CAA 记录阻止签发。
- 续期成功了,网站却显示证书过期:服务没有重载,见 NET::ERR_CERT_DATE_INVALID。
- 续期后客户端证书认证失效:Let's Encrypt 证书已不含 TLS 客户端认证 EKU,见 客户端认证 EKU 被移除。
常见问题
续期任务多久运行一次合适?
至少每天一次,常见做法是每天两次。客户端只会为到期的证书联系 CA,频繁检查几乎没有成本。用 ARI 时,每天检查也是客户端发现 CA 要求提前续期(比如批量吊销前)的唯一途径。
固定“到期前 30 天续期”还够用吗?
现在能用,但有效期变短后会出问题:45 天证书留 30 天余量还行,6 天证书做不到。让客户端根据证书有效期和 ARI 自动计算续期时间,不要写死天数。
手动上传到阿里云、腾讯云 CDN 的证书怎么办?
能换成云厂商托管证书的就换,这类手动上传的证书最容易过期。能用托管证书的用托管证书;不能的,在续期钩子里调用云厂商 API 上传;至少也要加到监控里。见 阿里云 CDN 配置 HTTPS 和 为 47 天证书做准备。
宝塔面板的证书会自动续期吗?
宝塔申请的 Let's Encrypt 证书由面板计划任务自动续签,前提是计划任务没被删、验证方式仍然可用(文件验证要求 80 端口可访问,DNS 验证要求 API 密钥有效)。见 宝塔面板配置 SSL 证书。