Nginx SSL 证书自动续期

大家好,今天想跟你们聊聊 Nginx 环境下 SSL 证书自动续期 的完整实践。现在的站点几乎都离不开 HTTPS,而 Let's Encrypt 提供的免费证书虽然只有 90 天有效期,但配合自动续期脚本,完全可以做到“一次部署,长期免维护”。下面把我在生产环境里跑的那套方案整理成文,希望对有需要的同学有所帮助。

---

1. 为何选 Let's Encrypt + Certbot

- 免费:不需要额外付费,适合个人站点或中小型业务。

- 自动化:Certbot 官方提供完整的自动申请、续期、部署流程。

- 插件丰富:支持 Nginx、Apache、Standalone 等多种模式,Nginx 插件甚至可以在续期后自动重新加载配置,省去手动干预。

如果你已经在使用商业证书,只要把 Renewal 脚本改成对应的证书路径,同样可以复用下面的思路。

---

2. 安装 Certbot 与 Nginx 插件

2.1 一键安装(以 Ubuntu/Debian 为例)

sudo apt update

sudo apt install -y certbot python3-certbot-nginx

2.2 验证安装

certbot --version

应该看到类似 "certbot 1.21.0" 的输出

2.3 申请第一张证书

假设你的域名已经解析到这台机器,Nginx 已经配置好对应的 server块。执行:

sudo certbot --nginx -d example.com -d www.example.com

Certbot 会自动修改 Nginx 配置,添加 listen 443 ssl http2; 等必要指令,并写入证书路径。申请成功后,浏览器访问 https://example.com 就会显示绿色小锁。

> 小技巧:如果只想先测试流程,可以使用 --dry-run 参数,Certbot 会模拟续期而不真正写入证书。

---

3. 配置自动续期任务

Let's Encrypt 证书的有效期是 90 天,Certbot 默认会在证书到期前 30 天尝试续期。我们只需要把这一步交给系统的定时任务。

3.1 使用 Cron(适用于大多数 Linux 发行版)

编辑系统 crontab:

sudo crontab -e

加入以下行(每天凌晨 3 点执行):

0 3 * * * /usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"

- --quiet:只输出错误,避免邮件打扰。

- --deploy-hook:在证书成功续期后立即执行指定命令,这里我们让它 reload Nginx,使新证书生效。

> 注意:如果你使用的是 systemctl restart nginx,会导致一次服务中断,建议使用 reload(平滑重载),用户体验更好。

3.2 使用 Systemd Timer(更可靠)

如果你更倾向于使用 systemd,可以创建如下两个文件:

1. /etc/systemd/system/certbot.timer(定时器)

[Unit]

Description=Run certbot renewal twice a day

[Timer]

OnCalendar=*-*-* 03,15:00:00

Persistent=true

[Install]

WantedBy=timers.target

2. /etc/systemd/system/certbot.service(实际任务)

[Unit]

Description=Let's Encrypt renewal

[Service]

Type=oneshot

ExecStart=/usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"

然后启用并启动:

sudo systemctl daemon-reload

sudo systemctl enable --now certbot.timer

这样每天会在 03:00 和 15:00 自动检查并续期,且系统会在机器重启后自动恢复定时任务。

---

4. 编写 Renewal Hook,确保 Nginx 平滑重载

Certbot 提供的 --deploy-hook 已经足够大多数场景,但如果你有更复杂的需求(比如先备份旧证书、发送通知等),可以自定义脚本。

4.1 简单的 deploy-hook 脚本

创建 /usr/local/bin/certbot-nginx-reload.sh

#!/bin/bash

certbot-nginx-reload.sh

记录日志

echo "$(date '+%Y-%m-%d %H:%M:%S') Cert renewed for $RENEWED_DOMAINS" >> /var/log/certbot-renew.log

平滑重载 Nginx

systemctl reload nginx

赋予执行权限:

sudo chmod +x /usr/local/bin/certbot-nginx-reload.sh

在 cron 或 systemd service 中使用:

--deploy-hook "/usr/local/bin/certbot-nginx-reload.sh"

4.2 常见坑点

| 场景 | 可能出现的错误 | 解决办法 |

|------|----------------|----------|

| Nginx 配置错误导致 reload 失败 | nginx: [error] reload 失败,证书已更新但服务仍用旧证书 | 在脚本里加入 nginx -t 检查配置,或使用 nginx -s reload 捕获返回码 |

| 证书路径权限不足 | Permission denied 读取 /etc/letsencrypt/live/... | 确保 Nginx 运行用户(通常是 www-data)对证书目录有读取权限 |

| 续期后 DNS 解析失效 | 续期时域名解析到别的机器,导致验证失败 | 使用 DNS-01 挑战或确保域名解析始终指向当前机器 |

---

5. 监控与告警

自动续期虽然省事,但一旦失手,站点会在证书过期后出现安全警告,影响用户体验甚至 SEO。下面两种监控方式可以帮你早发现、早处理。

5.1 检查证书到期时间

openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates

可以写一个小脚本放在监控平台(如 Prometheus + Alertmanager)中,阈值设为 7 天。

5.2 利用 Certbot 自带的日志

前面我们在 hook 里写入了 /var/log/certbot-renew.log,可以用 logwatchfluentd 采集,出现 Cert renewed 则说明续期成功;出现异常则触发告警。

5.3 第三方监控服务

UptimeRobotPingdomCertSpotter(专门检测证书到期)等,都提供邮件或 Slack 通知,建议至少开启一个作为兜底。

---

结语

通过 Let's Encrypt + Certbot 搭配 Nginx 的插件与 cron / systemd timer,我们完全可以实现“一键部署、长期自动续期”。关键点在于:

1. 使用 Certbot 的 Nginx 插件,让证书写入和配置更新一步到位。

2. 把续期任务交给系统定时,并加上 --deploy-hook 触发 nginx reload,实现平滑更新。

3. 做好监控,防止因意外导致证书失效。

只要把上面的步骤走通,后续基本不需要再手动干预,站点会一直在 HTTPS 的保护下安全运行。希望这篇文章能帮你省掉手动续期的麻烦,如果还有其他 Nginx 相关的需求,欢迎在评论区一起交流。祝部署顺利!