# SSL 证书自动续期：Certbot、acme.sh、lego 配置与检查

> 为 Certbot、acme.sh、lego、Caddy、Traefik、cert-manager、win-acme、宝塔配置并检查证书自动续期：定时任务、ARI、重载钩子和监控。

Source: https://ssl.sh/zh/guides/renew-certificates-automatically/
Last updated: 2026-11-10

SSL 证书自动续期要三样东西：至少每天运行一次 ACME 客户端的定时任务，续期后让服务加载新证书的重载钩子，以及能发现失败的外部监控。覆盖截至 2026 年 11 月的 Certbot、acme.sh、lego、Caddy、Traefik、cert-manager 和 win-acme，以及宝塔等面板。

## 前提条件

先要知道证书都在哪里、各自由什么工具签发。

- 能登录所有处理 TLS 的服务器、代理、集群和面板。
- 你的全部域名清单；用 [CT 证书查询](https://ssl.sh/zh/tools/ct-search/) 能看到为你的域名签发过的所有证书，容易找出被遗忘的那几张。
- 有权限修改这些系统上的 cron、systemd 定时器或计划任务。

## 第一步：盘点证书和客户端

每种 ACME 客户端都有列出证书的命令，先用它们查清有哪些证书、分别由谁续期：

```bash
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：

```bash
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`：

```bash
sudo grep -H renew_before_expiry /etc/letsencrypt/renewal/*.conf
```

## 第四步：重载所有用到证书的服务

磁盘上的证书换了，服务不重载就不会生效。用客户端的钩子机制：

```bash
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 续期钩子](https://ssl.sh/zh/guides/certbot-renewal-hooks/)。

## 验证

续期流程正常时，测试环境演练能成功完成，下一次实际续期后线上证书的到期时间会往后推。用 `--dry-run` 或测试环境演练续期，不消耗生产环境的频率限制：

```bash
sudo certbot renew --dry-run
```

acme.sh 和 lego 用测试环境（`--staging` 或 `--server https://acme-staging-v02.api.letsencrypt.org/directory`）。再用 [SSL 证书检查](https://ssl.sh/zh/tools/ssl-checker/) 或终端确认线上证书：

```bash
curl ssl.sh/example.com
```

域名多时用 [批量 SSL 检查](https://ssl.sh/zh/tools/bulk-ssl-checker/)。

## 自动续期

第二到第四步做好后续期就是自动的，剩下的是发现失败。Let's Encrypt 2025 年 6 月 4 日起不再发到期提醒邮件，需要自己设置告警：[ssl.sh 监控](https://ssl.sh/zh/monitor/)（开发中） 从外部检查线上证书并在到期前提醒，也能发现“续期成功但服务没重载”的情况。上面的调度方式已经能应对 Let's Encrypt 2027 年 2 月 10 日的 64 天、2028 年 2 月 16 日的 45 天默认有效期，以及[证书有效期时间线](https://ssl.sh/zh/timeline/certificate-validity/)上的行业上限。

## 常见问题排查

- **续期报 timeout during connect**：首次签发后 80 端口有变化（新防火墙规则、套了 CDN、加了跳转、备案失效被拦截），见 [certbot 连接超时](https://ssl.sh/zh/errors/certbot-timeout-during-connect/)。
- **too many certificates already issued**：脚本出错反复续期，见 [Let's Encrypt 频率限制](https://ssl.sh/zh/errors/lets-encrypt-rate-limit/)。按 ARI 续期可以避免这种情况。
- **CAA record prevents issuance**：首次签发后新加了 CAA 记录，见 [CAA 记录阻止签发](https://ssl.sh/zh/errors/caa-record-prevents-issuance/)。
- **续期成功了，网站却显示证书过期**：服务没有重载，见 [NET::ERR_CERT_DATE_INVALID](https://ssl.sh/zh/errors/net-err-cert-date-invalid/)。
- **续期后客户端证书认证失效**：Let's Encrypt 证书已不含 TLS 客户端认证 EKU，见 [客户端认证 EKU 被移除](https://ssl.sh/zh/errors/client-auth-eku-removed/)。
