Certbot 自动续期证书:从签发到永久免维护(Nginx 实战)

证书过期不是"网站变黄",是浏览器直接红屏拒绝访问,用户没法点"继续访问"跳过。而这件事完全可以不发生——Certbot 装上之后,剩下十年你都不用再管证书。

这篇按"能直接复制跑"的标准写:装、签、自动续、验证、告警、排错,外加 2027 年证书有效期缩短前你现在就该做的三件事。

一、结论先给:四步跑完,之后全自动

# 1)安装(Ubuntu / Debian,snap 版版本最新,推荐)
sudo apt remove -y certbot 2>/dev/null
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/bin/certbot

# 2)签发(--nginx 插件会自动改 Nginx 配置并加 80→443 跳转)
sudo certbot --nginx -d example.com -d www.example.com

# 3)确认自动续期的定时器在跑
sudo systemctl status snap.certbot.renew.timer   # 要看到 active (waiting)

# 4)干跑验证(不真签发,专门用来提前暴露问题)
sudo certbot renew --dry-run

第 4 步必须当天做。定时器在跑不等于能续成功——端口被墙、DNS 改了、Nginx 配置被改坏,都会在真要续期的那一天才炸。

二、装哪个版本:snap 还是 apt

安装方式 版本 自动续期载体 建议
snap install --classic certbot 官方最新 systemd timer snap.certbot.renew.timer 推荐,Ubuntu 24.04 首选
apt install certbot python3-certbot-nginx 发行版仓库,通常偏旧 certbot.timer 或 /etc/cron.d/certbot 内网离线环境可用
dnf install certbot python3-certbot-nginx(RHEL / Rocky / Alma) 仓库版本 certbot-renew.timer 需要 epel-release

先查版本,低于 4.1.0 的一定要升级:

certbot --version

4.1.0(2025-06 发布)开始,certbot renew 会自动读取 ARI(ACME Renewal Information)——由 CA 告诉客户端"这张证现在该续了",而不是傻等写死的天数。这在后面 2027 年那节是硬要求。

两种安装方式不要混装,否则 which -a certbot 会出现两个,定时任务跑的可能不是你以为的那个。

三、签发:三种验证方式怎么选

方式 命令 适用场景 注意点
--nginx 插件 certbot --nginx -d a.com -d www.a.com Nginx 在跑,想让它顺手改配置 改完自动 test + reload
webroot certbot certonly --webroot -w /var/www/html -d a.com 只想拿证书,配置自己写 要求 80 端口可访问 /.well-known/
standalone certbot certonly --standalone -d a.com 机器上没有 Web 服务 需要临时占用 80,得先停 Nginx
DNS-01 certbot certonly --dns-cloudflare ... 通配符证书 *.a.com 只有 DNS-01 能签通配符,要 DNS 服务商 API 密钥

通配符只能走 DNS-01,别浪费时间试 HTTP-01:

sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare
# /root/cloudflare.ini 里放 dns_cloudflare_api_token,权限 chmod 600
sudo certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials /root/cloudflare.ini \
  -d example.com -d '*.example.com'

用 webroot 时,Nginx 的这个 location 要常驻,否则续期那天 404:

location ^~ /.well-known/acme-challenge/ {
    root /var/www/html;
    default_type "text/plain";
}
location / { return 301 https://$host$request_uri; }

四、自动续期的原理(知道它什么时候真干活)

sudo systemctl cat snap.certbot.renew.timer
# OnCalendar=*-*-* 00,12:00:00      每天 0 点和 12 点各一次
# RandomizedDelaySec=...            随机延迟,避免全球机器同时打 CA

关键点:

  • 一天两次只是"检查",不是"续期"。默认只在剩余有效期 ≤ 30 天时才真的发起续期(配置在 /etc/letsencrypt/renewal/域名.conf 的 renew_before_expiry)。
  • Certbot 4.1.0+ 会采纳 ARI 建议的续期窗口,大致是有效期的三分之二处,比写死 30 天更合理。
  • 续期成功会写日志到 /var/log/letsencrypt/letsencrypt.log,排查只看这一个文件就够。

想手动确认当前所有证书的状态:

sudo certbot certificates
# Expiry Date: 2026-12-21 (VALID: 89 days)

五、续完必须让 Nginx 吃到新证书

证书文件换了,但 Nginx 内存里还是旧的,不 reload 就继续用旧证,直到过期。三种做法选一个:

做法 A(推荐):放 deploy hook,全局生效

sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh >/dev/null <<'EOF'
#!/bin/bash
systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

放在 renewal-hooks/deploy/ 下的脚本,只在真的续期成功时执行,比每次定时器跑都 reload 干净得多。

做法 B:命令上直接带

sudo certbot renew --quiet --deploy-hook "systemctl reload nginx"

做法 C:用 --nginx 插件签发的,插件自带 reload,不用管。

注意用 reload 不是 restart:reload 不断连接,restart 会短暂中断。

六、没有 systemd 就用 crontab

老系统或者容器里没有 systemd 时:

sudo crontab -e
# 每天 3:30 和 15:30 各检查一次,随机睡 0-30 分钟错峰
30 3,15 * * * sleep $((RANDOM \% 1800)) && /usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"

Cron 表达式别写错,写错就是"以为在跑其实没跑":Cron 表达式在线解析 可以直接验证。

检查有没有真的执行过:

grep -i certbot /var/log/syslog | tail -20
# 或 systemd 环境:
journalctl -u snap.certbot.renew.service --since "7 days ago"

七、监控告警:这一步 90% 的人没做

Let's Encrypt 从 2025-06-04 起已经不发"证书即将过期"邮件了,所有账户邮箱都删了。也就是说:续期失败 → 没人告诉你 → 到期当天红屏。

自己加一道检查,30 行以内:

sudo tee /usr/local/bin/cert-expiry-check.sh >/dev/null <<'EOF'
#!/bin/bash
# 剩余天数低于 20 天就告警(可接企业微信/钉钉/飞书 webhook)
WARN_DAYS=20
WEBHOOK="https://your-webhook-url"
for cert in /etc/letsencrypt/live/*/fullchain.pem; do
  [ -f "$cert" ] || continue
  name=$(basename $(dirname "$cert"))
  end=$(openssl x509 -enddate -noout -in "$cert" | cut -d= -f2)
  left=$(( ($(date -d "$end" +%s) - $(date +%s)) / 86400 ))
  if [ "$left" -lt "$WARN_DAYS" ]; then
    msg="[证书告警] $name 剩余 $left 天($end)"
    echo "$msg"
    curl -s -X POST "$WEBHOOK" -H 'Content-Type: application/json' \
      -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$msg\"}}" >/dev/null
  fi
done
EOF
sudo chmod +x /usr/local/bin/cert-expiry-check.sh

再挂到 crontab,每天上午跑一次:

0 9 * * * /usr/local/bin/cert-expiry-check.sh

外部视角也值得加一道:HTTP 状态码查询 和 HTTP/Ping 检测 从站外看证书链是否正常、有没有中间证书缺失——有些问题本机 openssl 看不出来,浏览器却会报错。

八、续期失败的常见原因(按出现频率排)

报错 真因 处理
Connection refused / Timeout during challenge 80 端口不通(ufw、云安全组、CDN 回源) sudo ufw allow 80/tcp + 检查云厂商安全组
DNS problem: NXDOMAIN 域名 A 记录没指向这台机,或已解析到别处 dig +short 域名 核对
Unauthorized / 404 挑战文件 /.well-known/acme-challenge/ 被 301 到 HTTPS 或被 location 拦 加第三节那段 location
too many certificates already issued 触发速率限制(同域名每周 50 张、重复证书每周 5 张) 等一周;调试一律加 --dry-run 或 --staging
nginx: [emerg] 之后 certbot 改不动配置 Nginx 配置本身有错 先 nginx -t 修好再续
证书明明续了但浏览器还报旧日期 没 reload,或 CDN 上还挂着旧证 systemctl reload nginx + CDN 侧重新上传证书

调试请一律走 staging 环境,不消耗正式额度:

sudo certbot renew --dry-run          # 干跑,推荐
sudo certbot certonly --staging ...   # 走测试 CA

九、2027 年之前必须改的三件事

Let's Encrypt 已公布时间表:2027-02-10 起默认证书从 90 天降到 64 天,2028-02-16 进一步降到 45 天(想提前适应,现在可以用 tlsserver profile 拿 45 天证书)。

对自动续期的影响:

  1. Certbot 升到 4.1.0 以上,让 ARI 决定续期时机。写死"每 60 天续一次"的脚本,在 45 天时代必然有一次来不及。
  2. 检查频率提高:一天两次够了,但确认定时器真的 enable 了:systemctl is-enabled snap.certbot.renew.timer。
  3. 告警必须有:有效期越短,一次失败留给你的补救窗口越小。20 天告警线可以,45 天证书建议提到 15 天。

一句话:把"什么时候续"交给 ARI,把"续没续上"交给监控,人只需要在告警时介入。

十、小结

动作 命令
装 snap install --classic certbot
签 certbot --nginx -d 域名
续(自动) systemd timer 每天两次,剩余 ≤30 天或按 ARI 触发
重载 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
验证 certbot renew --dry-run、certbot certificates
告警 剩余天数脚本 + 企业微信/钉钉 webhook

配完之后建议每季度做一次 certbot renew --dry-run,成本 10 秒,能挡掉 99% 的"到期才发现"。


相关工具:Linux 命令速查 · SSH 密钥检查 · Cron 表达式在线解析 · HTTP 状态码查询

延伸阅读:Nginx 配置参数解析与优化 · Nginx 跑满并发:Nginx + 系统内核调优 · Ubuntu 安装 Docker

还有 65 个免费在线工具

纯前端实现,不用注册,数据不上传服务器。

浏览全部工具