前言:在生产环境中,使用Let's Encrypt免费证书是主流选择,但90%的运维同学都踩过同一个坑:证书能手动申请、能自动续期,但续期后Nginx不加载新证书,最终导致业务访问异常。
核心问题根本不是Certbot没续期成功,而是 没有给自动续期流程永久绑定「证书同步+服务重载」的钩子脚本。本文基于生产环境实战经验,提供一套完整、可落地、零故障的全自动续期方案,覆盖CentOS/Ubuntu双系统,彻底解决证书过期问题。
注:本文以 Cloudflare 作为 DNS 验证服务商示例,核心原理与操作逻辑完全通用,其他支持 ACME DNS-01 验证的域名商(如阿里云、腾讯云、DNSPod 等),仅需替换对应 DNS 插件与凭证配置,即可复用整套全自动续期方案。
一、前置准备:Cloudflare端API令牌创建(DNS验证前提)
使用Cloudflare DNS验证的优势是无需暴露80/443端口,支持泛域名证书,适合生产环境内网/非Web服务器场景。
-
登录Cloudflare后台,进入「我的个人资料」→ 左侧「API令牌」→ 「创建令牌」
-
选择「创建自定义令牌」,按以下规则配置:
配置项 配置内容 令牌名称 Certbot-生产服务器-API令牌(可自定义) 权限 区域 - DNS - 编辑(Edit) 区域资源 包括 - 特定区域 - 你的主域名(如 example.com)客户端IP筛选 等于 - 你的生产服务器公网IP(可选,提升安全性) 令牌有效期 建议永久有效(按需调整) -
点击「继续以显示摘要」→ 「创建令牌」,复制生成的令牌(仅显示1次,务必保存)
二、服务器端环境准备(CentOS/Ubuntu双版本)
核心说明
推荐使用Snap版Certbot,官方维护、版本最新、兼容性最好,避免系统自带yum/apt源的旧版本出现功能缺失、兼容性问题。
版本1:CentOS/RHEL 7/8/9 系列
bash
# 1. 安装EPEL源(CentOS安装Snap的前置依赖)
sudo yum install epel-release -y
# 2. 安装Snapd
sudo yum install snapd -y
# 3. 启动Snapd服务并设置开机自启
sudo systemctl enable --now snapd.socket
# 4. 创建软链接,让snap命令全局可用
sudo ln -s /var/lib/snapd/snap /snap
# 5. 验证Snap安装(可选)
snap version
版本2:Ubuntu/Debian 系列
bash
# 1. 更新系统源
sudo apt update -y
# 2. 安装Snapd(Ubuntu默认自带,无则执行)
sudo apt install snapd -y
# 3. 验证Snap安装(可选)
snap version
通用步骤:安装Certbot及Cloudflare DNS插件
bash
# 1. 更新Snap核心组件,避免版本兼容问题
sudo snap install core && sudo snap refresh core
# 2. 卸载系统旧版Certbot(如有,避免冲突)
# CentOS执行:
sudo yum remove certbot -y
# Ubuntu执行:
sudo apt remove certbot -y
# 3. 安装Snap版Certbot并创建全局软链接
sudo snap install --classic certbot && sudo ln -s /snap/bin/certbot /usr/bin/certbot
# 4. 授权Certbot信任插件的root操作(解决插件权限报错)
sudo snap set certbot trust-plugin-with-root=ok
# 5. 安装Cloudflare DNS插件并创建全局软链接
sudo snap install certbot-dns-cloudflare && sudo ln -s /snap/bin/certbot-dns-cloudflare /usr/bin/certbot-dns-cloudflare
三、Cloudflare API凭证配置
bash
# 1. 创建Certbot专属配置目录
sudo mkdir -p /etc/certbot
# 2. 编辑凭证文件
sudo nano /etc/certbot/cloudflare.ini
在编辑器中粘贴以下内容,替换为你自己的API令牌:
ini
dns_cloudflare_api_token = 你刚刚在Cloudflare创建的API令牌
保存退出:按Ctrl+O → 回车确认 → 按Ctrl+X。
bash
# 3. 锁死文件权限(仅root可读,防止令牌泄露,Certbot强制要求)
sudo chmod 600 /etc/certbot/cloudflare.ini
四、申请泛域名SSL证书
执行以下命令,替换域名和邮箱为你的真实信息,全程无需手动干预,自动完成DNS验证和证书签发:
bash
sudo certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /etc/certbot/cloudflare.ini \
--dns-cloudflare-propagation-seconds 60 \
-d "example.com" -d "*.example.com" \
--email 你的运维邮箱@xxx.com \
--agree-tos --non-interactive
- 参数说明:
--dns-cloudflare-propagation-seconds 60:给DNS记录传播预留60秒,避免验证失败--non-interactive:非交互式执行,适合自动化脚本- 邮箱用于接收证书到期提醒,务必填写真实邮箱
执行成功后,证书会默认保存在/etc/letsencrypt/live/example.com/目录下。
五、Nginx证书替换与服务配置验证
1. 进入Nginx证书存放目录(按你的实际路径调整)
bash
cd /etc/nginx/ssl/
2. 备份旧证书(出错可回滚,生产环境必做)
bash
sudo cp example.com_certificate.pem example.com_certificate.pem.old
sudo cp example.com_private.key example.com_private.key.old
3. 复制新生成的证书替换旧文件
bash
sudo cp /etc/letsencrypt/live/example.com/fullchain.pem /etc/nginx/ssl/example.com_certificate.pem
sudo cp /etc/letsencrypt/live/example.com/privkey.pem /etc/nginx/ssl/example.com_private.key
4. 验证Nginx配置语法(关键!防止配置错误导致服务崩溃)
bash
sudo nginx -t
5. 重载Nginx加载新证书(温和重载,不中断业务,生产环境禁止用restart)
bash
sudo systemctl reload nginx
6. 验证Nginx运行状态(可选)
bash
sudo systemctl status nginx
六、核心重点:全自动续期钩子永久绑定(绝对不能漏的关键步骤)
踩坑预警
90%的证书故障都源于此:很多同学会用 sudo certbot renew --deploy-hook xxx.sh 测试钩子脚本,但这个参数是临时生效 ,仅对当前这一次renew命令有效,Certbot自带的定时自动续期不会执行这个脚本!
必须用 certbot reconfigure 命令,将钩子脚本永久写入证书的续期配置文件,才能实现真正的全自动续期。
步骤1:创建续期钩子脚本
bash
sudo nano /usr/local/bin/certbot_example_renew.sh
在编辑器中粘贴以下内容,无需修改核心逻辑,仅需调整证书路径和Nginx重载命令适配你的环境:
bash
#!/bin/bash
# 复制续期后的新证书到Nginx目录
sudo cp /etc/letsencrypt/live/example.com/fullchain.pem /etc/nginx/ssl/example.com_certificate.pem
sudo cp /etc/letsencrypt/live/example.com/privkey.pem /etc/nginx/ssl/example.com_private.key
# 温和重载Nginx,不中断业务
sudo nginx -s reload
保存退出:按Ctrl+O → 回车确认 → 按Ctrl+X。
步骤2:给脚本添加执行权限
bash
sudo chmod +x /usr/local/bin/certbot_example_renew.sh
步骤3:永久绑定钩子,后续自动续期会自动执行脚本(核心中的核心)
bash
sudo certbot reconfigure --cert-name example.com --deploy-hook /usr/local/bin/certbot_example_renew.sh
执行后会出现交互提示:
You are attempting to set a --deploy-hook. Would you like Certbot to run deploy hooks when it performs a dry run with the new settings?
(R)un deploy hooks/(D)o not run deploy hooks:
输入R回车,会立刻执行一次钩子脚本做验证,同时将配置永久写入文件。
步骤4:只读验证:确认绑定成功(无任何修改,生产环境安全)
不同版本的Certbot会自动兼容deploy_hook和renew_hook两个参数,两个命令都执行,确保能搜到配置:
bash
# 验证deploy_hook配置
sudo grep -i "deploy_hook" /etc/letsencrypt/renewal/example.com.conf
# 验证renew_hook配置(Snap版Certbot会自动转换为此参数)
sudo grep -i "renew_hook" /etc/letsencrypt/renewal/example.com.conf
✅ 成功标准:执行后输出deploy_hook = 你的脚本完整路径或renew_hook = 你的脚本完整路径,说明永久绑定成功。
七、全流程有效性验证
1. 模拟续期验证(零风险,不实际修改证书)
bash
sudo certbot renew --dry-run
✅ 成功标准:输出中出现Running deploy-hook command: /usr/local/bin/certbot_example_renew.sh或Running renew-hook command: /usr/local/bin/certbot_example_renew.sh,说明自动续期时会自动执行脚本。
2. OpenSSL验证证书有效期(最直观)
bash
sudo openssl x509 -in /etc/nginx/ssl/example.com_certificate.pem -noout -dates
✅ 成功标准:输出notBefore和notAfter,显示证书的最新有效期。
3. 浏览器验证
强制刷新浏览器(Ctrl+F5)或用无痕模式访问你的域名,查看证书有效期,确认已更新为最新签发的证书。
八、生产环境避坑指南
- 临时钩子≠永久配置 :
--deploy-hook跟在renew后是临时生效,只有跟在reconfigure后才是永久写入配置,这是最核心的坑。 - 版本兼容问题 :Snap版Certbot会自动将
--deploy-hook转换为renew_hook写入配置文件,两个参数效果完全一致,无需纠结名称,只要grep能搜到就代表生效。 - 脚本权限问题 :钩子脚本必须添加
x执行权限,路径必须用绝对路径,否则自动续期时会执行失败。 - Nginx重载规范 :生产环境必须用
reload重载,禁止用restart,reload是温和加载新配置,不会中断现有连接,restart会重启服务,导致业务中断。 - 缓存问题:验证证书时,浏览器/CDN会缓存旧证书,务必用强制刷新或无痕模式验证,避免误判。
- 权限最小化:Cloudflare API令牌仅开放指定域名的DNS编辑权限,不要用全局API密钥,降低泄露风险。
九、后续复查计划
Let's Encrypt证书有效期为90天,Certbot默认会在证书剩余30天时触发自动续期,推荐两个复查时间点,按需选择:
- 常规复查:证书到期前30天(如6月15日到期,5月15日复查),确认自动续期已执行,证书已同步。
- 保守复查:证书到期前10天(如6月15日到期,6月6日复查),距离到期有充足的缓冲时间,即使出现异常也有足够时间处理,零业务风险。
复查仅需执行本文「第七部分」的3条验证命令,1分钟即可完成。
结尾
按照本文流程配置完成后,你的生产环境证书就实现了真正的「全自动签发-续期-同步-重载」全流程闭环,无需任何人工干预,彻底杜绝证书过期导致的业务故障。
