如果你在 Linux 服务器上用 Certbot 给 Nginx 续期证书,续期这件事大概很少出问题。Certbot 是 EFF 维护的免费开源 ACME 客户端,Let's Encrypt 推荐有 shell 权限的用户优先用它。它会申请证书,并用 systemd 定时器或 cron 设置自动续期(取决于安装方式)。它的 Nginx、Apache 插件能把证书写进配置,DNS 插件能处理通配符证书需要的 DNS-01 验证。
麻烦通常出在规模变了以后:服务器从一台变成几台,前面加了阿里云或腾讯云的 CDN 和负载均衡,同一张证书还要传到 OSS、WAF 这些云产品上。于是有了一堆 deploy hook 和 crontab 脚本,或者每次续期后登录云控制台手动上传。Certbot 本身没出问题,难管的是续期之后的部署。
下面分三种情况说:什么时候继续用 Certbot,什么时候换一个自己部署的客户端,什么时候换成托管服务,让它把部署也一起管了。最后讲怎么在不改 Nginx 配置的前提下迁移,以及怎么确认迁移已经完成。
一台服务器:继续用 Certbot
如果你的情况是这样:只有一台服务器,Certbot 的 Nginx 或 Apache 插件负责安装证书和重载,定时器在正常跑,这张证书也没有别的地方要用,那就不用换。
偶尔确认一下它还在工作就够了:
# 看续期定时器是否存在、下次什么时候运行(cron 方式安装的话看 crontab)
systemctl list-timers | grep certbot
# 模拟一次续期,不会真的替换证书
sudo certbot renew --dry-run
两条都正常,就不需要做别的。
想换一个自己部署的 ACME 客户端
如果你只是想换个客户端,部署还是自己管,常见的选择有这几个:
- acme.sh:用 Shell 写的 ACME 客户端,自带大量 DNS 服务商接口,国内用的人很多。
- lego:Go 写的 ACME 客户端,单个二进制文件,也可以当作库使用。
- Caddy:Web 服务器自带自动 HTTPS,如果你愿意把 Nginx 换掉,证书这件事就不用单独管了。
- cert-manager:在 Kubernetes 集群里签发和续期证书,适合服务已经跑在 K8s 上的情况。
更多客户端见 Let's Encrypt 的客户端列表。想按类别比较这些工具,可以看SSL 证书自动化工具对比。
acme.sh 自带通过 SSH 部署到其他服务器的 hook,也能对接部分云服务,如果它覆盖了你的部署位置,而且你愿意自己维护,也可以用它。其他几个客户端和 Certbot 一样,往别的服务器和云产品推送证书要自己写脚本、自己维护。
同一张证书要部署到多个地方:用 LapseZero
如果同一张证书要部署到几台服务器和若干云产品,而你现在靠 hook 和脚本推送,还想知道每个位置是不是真的换上了新证书,推荐用 LapseZero。它是一个托管服务,负责签发证书、自动续期、部署到服务器和云产品,还能监控 HTTPS 站点的证书。LapseZero 会把签发和续期一起接管,不能只用它分发证书、签发仍交给 Certbot。
Certbot 在这种场景下的问题
Certbot 能做部署:--deploy-hook 会在续期成功后执行,另外还有 pre hook 和 post hook。代价是推送到其他机器、调用云 API 的逻辑都要自己写在 hook 里。实际情况往往是脚本只有写它的人看得懂,而且 hook 中途失败时没有机制把旧文件放回去。
更难发现的问题是,Certbot 报告续期成功,但某台服务器或某个 CDN 上可能还是旧证书。也许 scp 失败了,也许重载没执行,也许 CDN 换了新证书但源站没换。hook 出错时会有错误输出,但 Certbot 照样报告续期成功,没人专门去查的话,往往要等证书快过期、有人报错时才会发现。
LapseZero 怎么处理
- 签发和续期:通过 DNS-01 签发,支持通配符。剩余有效期不到三分之一时自动续期,90 天的证书大约在到期前 30 天续期。DNS 验证有两种方式:填 DNS 服务商的 API 密钥;或者一次性添加一条 CNAME 做委派验证,这样不用交出 DNS 密钥。
- 部署到服务器:可以用 SSH,也可以用开源的部署客户端 agent(Go 编写,GitHub 和 Gitee 上搜
lapsezero-agent)。agent 通过出站 HTTPS 连接平台,不用开放入站端口,平台也不保存 SSH 凭证。通过 agent 还能部署到 1Panel 和 Nginx Proxy Manager。 - 部署到云产品:
- 阿里云:CDN、全站加速 DCDN、ESA、OSS、CLB、ALB、NLB、WAF、数字证书管理服务
- 腾讯云:CDN、EdgeOne、CLB、COS、WAF、SSL 证书
- 华为云:CDN、ELB
- 七牛云 CDN、又拍云 CDN
- 火山引擎:CDN、CLB、ALB
- AWS:CloudFront、ALB、NLB、API Gateway、ACM、Amplify;以及 Google Cloud Certificate Manager、Azure Key Vault
- 部署失败的处理:部署到服务器时,要么完整替换,要么保持原样。写入或重载失败会恢复旧证书,通知里会注明已回滚。每个部署位置单独记录结果,失败时通过邮件、钉钉、飞书、Slack、Telegram 或 Webhook 通知。每个位置还可以设置允许部署的时间段,比如只在工作时间部署。
- 确认新证书已生效:可以开启部署后检查。平台会连接公网 HTTPS 地址,比对实际返回的证书指纹;用 agent 部署的服务器还可以在本机检查。前面有 CDN 时这项检查很有用,因为 CDN 返回新证书并不代表源站也换好了。
- 监控:任何公网 HTTPS 地址的证书都可以监控,不需要凭证,不由 LapseZero 部署的站点也可以。
对比
| Certbot | LapseZero | |
|---|---|---|
| 形态 | 本机命令行客户端 | 托管服务,配合可选的 agent |
| 部署到本机 Nginx/Apache | 插件 | SSH 或 agent,沿用原路径和重载命令 |
| 部署到其他服务器 | 自己写 hook | SSH 或 agent |
| 部署到云产品 | 自己写 hook 调用云 API | 内置上面列出的产品 |
| 部署失败 | hook 中途失败不会恢复旧文件 | 服务器部署恢复旧证书,并通知已回滚 |
| 确认新证书生效 | 自己检查 | 可选部署后检查,比对证书指纹 |
| 失败通知 | 自己写进脚本 | 邮件、钉钉、飞书、Slack、Telegram、Webhook |
| 价格 | 免费开源 | 有免费版,付费版 6 元/月起 |
价格
国内站的价格(域名 / 部署位置 / 监控数量):
- 免费版:3 / 5 / 5,没有使用期限
- 入门版:6 元/月(60 元/年),10 / 20 / 20
- 专业版:15 元/月(150 元/年),30 / 80 / 50
- 团队版:39 元/月(390 元/年),100 / 200 / 200
比如一个域名部署到两台服务器、一个 CDN 和一个负载均衡,会占用 5 个部署位置中的 4 个,免费版就够用。
私钥、权限和退出
私钥
私钥由平台在签发时生成。证书、私钥,以及 DNS、云厂商和 SSH 凭证都用 AES-256-GCM 加密存储,凭证保存后控制台和接口都不会再显示。已签发的证书(含私钥)随时可以在控制台下载。更多细节见站内的 安全说明。
云账号权限
用 LapseZero 以后,云厂商凭证保存在平台上。添加云厂商账号时,控制台会给出一份权限策略,可以直接粘贴到阿里云 RAM、腾讯云 CAM 这类访问控制里。策略只包含平台需要调用的证书和资源操作,不需要管理员密钥。DNS 方面如果不想交出密钥,可以用 CNAME 委派验证。
agent 的权限
agent 作为 systemd 服务以 root 权限运行,因为它要写入证书文件并执行重载命令。重载命令由你自己配置,比如 systemctl reload nginx。卸载命令是 lapsezero-agent uninstall。
部署失败
因为连不上服务器而部署失败时,几分钟内会自动重试。服务器离线时间更长时,这次部署会被记为失败并发出通知,等服务器恢复后在控制台手动重试。
退回 Certbot
证书文件一直留在服务器原来的路径上,所以无论是否停用 LapseZero,Nginx 都能照常运行。要回到 Certbot,把之前移走的续期配置放回 /etc/letsencrypt/renewal/,然后执行:
sudo certbot renew --cert-name <name> --force-renewal
从 Certbot 迁到 LapseZero,不改 Nginx 配置
下面以 agent 方式迁移为例。
-
在服务器上安装 agent。安装后它会执行
nginx -T(只读),列出所有 server 块和对应的证书路径。位于/etc/letsencrypt/live/下的证书会被标记为 Certbot 管理;如果有 acme.sh 管理的证书也会标出来;宝塔站点会提示你关闭宝塔自带的自动续期。扫描过程不会读取私钥内容。 -
检查有没有一张证书覆盖不了的 server 块。LapseZero 按添加的域名签发证书,一个域名一张:要么是单个名称(根域名可以选择同时包含 www),要么是通配符
*.example.com(同时包含example.com)。如果一个 server 块里同时写了example.com和example.org,或者a.example.com和b.c.example.com,任何一张这样签出来的证书都覆盖不了这个块,而同一个 server 块里的域名用的是同一张证书。所以接管之前要先把它拆成多个 server 块,每个块各自引用自己的证书。 -
勾选要接管的站点。LapseZero 会建一个部署目标,沿用原来的证书路径和重载命令,Nginx 配置不需要改。接管这一步不会立即部署。如果这个域名在 LapseZero 里还没有证书,接管后可以直接签发,签发完成后按正常流程部署到服务器。
-
确认新证书已经部署并生效:控制台里这个部署位置的记录显示成功,部署后检查的指纹和新证书一致。如果前面有 CDN,CDN 和源站都要检查。
-
停掉 Certbot 对这张证书的续期。LapseZero 只会提醒,不会替你停。如果两边同时续期,会互相覆盖证书文件。做法是把续期配置移出
/etc/letsencrypt/renewal/目录:bashsudo mkdir -p /root/certbot-renewal-backup sudo mv /etc/letsencrypt/renewal/<name>.conf /root/certbot-renewal-backup/不要用
certbot delete,它会删掉/etc/letsencrypt/live/<name>/下的文件,而 Nginx 正在引用这些文件。另外,以前往别处推送这张证书的 hook 也要一并删掉。
把第 5 步放在第 4 步之后,是为了在切换过程中始终有一方负责续期,不出现没人管的空档。
怎么确认交接完成
满足下面几条,就可以认为交接已经完成:
- 在 LapseZero 控制台里,这个域名的每个部署位置(服务器、CDN、负载均衡等)都有成功记录,部署后检查返回的指纹和新证书一致。
- 执行
sudo certbot certificates时已经看不到这张证书,说明 Certbot 不会再去续期它。 - 以前推送这张证书的 hook 和 crontab 条目都已经删除。
之后续期、部署和失败通知都由 LapseZero 处理,某个位置没换上新证书时会收到通知。