使用 Cloudflare DNS-01 申请 Let’s Encrypt 证书
校对日期:2026-09-04。本文适用于 Ubuntu 服务器,域名 DNS 由 Cloudflare 托管,并由 Nginx 加载证书的场景。
DNS-01 验证不需要对外开放 80 端口,也是申请通配符证书的方式。Certbot 会记住首次申请时使用的 Cloudflare 插件和参数,以后续签时会自动复用。
1. 安装 Certbot 和 Cloudflare 插件
Certbot 官方对大多数 Ubuntu 用户推荐使用 Snap,但也可以使用 Ubuntu/Debian 软件源中的 apt 版本。两种方案二选一,不要混装 Certbot 主程序和不同来源的 DNS 插件。如果服务器已经安装了可正常续签的 Certbot,可直接跳过本节。
方案 A:Snap(官方推荐)
sudo apt update
sudo apt install -y snapd
sudo snap install --classic certbot如果 /usr/local/bin/certbot 尚不存在,创建官方建议的命令链接:
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot允许 DNS 插件与 Certbot 拥有相同的 classic 权限,然后安装 Cloudflare 插件:
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare方案 B:apt(备选)
如果希望 Certbot 由系统软件源统一管理,可安装 Ubuntu/Debian 提供的 Certbot 和 Cloudflare 插件:
sudo apt update
sudo apt install -y certbot python3-certbot-dns-cloudflareapt 版本由发行版维护,版本可能落后于 Certbot 上游最新稳定版。DNS-01、自动续签和 deploy hook 均可使用;如果某个命令行参数无法识别,应以已安装版本的 certbot --help 为准,或改用 Snap 版本。定时续签可能由 certbot.timer 或发行版提供的 cron 执行,仍应按第 5 节的命令确认。
验证安装
certbot --version
sudo certbot pluginsplugins 的输出中应当包含 dns-cloudflare。
2. 创建最小权限的 Cloudflare API Token
- 打开 Cloudflare API Tokens。
- 选择
Create Token,然后使用Edit zone DNS模板。 - 权限保留
Zone→DNS→Edit/Write。 - 在 Zone Resources 中选择
Specific Zone,仅授权需要申请证书的域名。 - 创建并立即复制 Token;Cloudflare 不会再次显示完整密钥。
不要使用权限过大的 Global API Key。Certbot Cloudflare 插件官方文档要求的最小权限是目标 Zone 的 Zone:DNS:Edit。
3. 保存 Cloudflare 凭据
将凭据放到仅 root 可读的目录:
sudo install -d -m 700 /etc/letsencrypt/secrets
sudo nano /etc/letsencrypt/secrets/cloudflare.ini写入:
# Cloudflare API token used by Certbot
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN限制文件权限:
sudo chmod 600 /etc/letsencrypt/secrets/cloudflare.iniCertbot 会在续签配置中记录这个文件的路径,不会复制 Token 内容。不要移动或删除该文件,否则自动续签会失败。
4. 申请证书
以同时覆盖根域名和一级子域名的证书为例,将 example.com 替换为自己的域名:
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/secrets/cloudflare.ini \
-d example.com \
-d '*.example.com'通配符域名必须加引号,避免被 Shell 展开。*.example.com 不覆盖 example.com,因此如果两者都需要,必须同时传入两个 -d。
Cloudflare 插件默认等待 10 秒后再验证 DNS。只有在实际遇到 DNS 传播不及时时,才需要增加等待时间,例如:
--dns-cloudflare-propagation-seconds 30查看 Certbot 管理的证书和实际路径:
sudo certbot certificates常用文件位于:
- 完整证书链:
/etc/letsencrypt/live/<certificate-name>/fullchain.pem - 私钥:
/etc/letsencrypt/live/<certificate-name>/privkey.pem
live 下的文件是会随续签自动更新的链接,使用证书的服务应直接引用这些路径,不要手工复制证书。
5. 配置续签成功后的 Nginx Hook
确认自动续签
大多数 Certbot 安装方式已预置定时任务,会周期性执行 certbot renew。Snap 版本也自带续签计时器,因此不需要再添加 crontab。
查看当前的安装来源:
command -v certbot
readlink -f "$(command -v certbot)"查找已有的 systemd 计时器:
systemctl list-timers --all | grep -i certbotSnap 安装通常可以继续查看:
systemctl status snap.certbot.renew.timer
snap services certbotapt/deb 安装通常使用:
systemctl status certbot.timer个别发行版可能使用 cron,可以检查:
sudo grep -R "certbot renew" /etc/crontab /etc/cron.* 2>/dev/null创建永久 deploy hook
下面的参数只对当次手工执行生效,不会因此成为以后自动续签的永久配置:
sudo certbot renew --deploy-hook "systemctl reload nginx"永久做法是把可执行脚本放入 Certbot 的 renewal-hooks/deploy 目录。deploy hook 只会在证书成功签发或续签后执行;没有证书需要续签时,不会 reload Nginx。
先确认命令的绝对路径:
command -v nginx
command -v systemctl创建 hook:
sudo install -d -m 755 /etc/letsencrypt/renewal-hooks/deploy
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh写入以下内容。如果上一步的命令路径不同,应按实际输出修改:
#!/bin/sh
/usr/sbin/nginx -t -q && /usr/bin/systemctl reload nginx赋予执行权限:
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.shnginx -t 先检查配置;只有检查成功,&& 后的 reload 才会执行。-q 会隐藏配置检查成功时的非错误信息,但真正的配置错误仍会输出并阻止 reload。
目录中的 deploy hook 对该 Certbot 配置管理的所有证书生效。如果同一台机器还管理不供 Nginx 使用的证书,应根据
RENEWED_DOMAINS或RENEWED_LINEAGE在脚本内做条件判断。
测试续签和 hook
普通 --dry-run 只测试续签,默认不执行 deploy hook:
sudo certbot renew --dry-run要同时测试新增的 Nginx hook,使用:
sudo certbot renew --dry-run --run-deploy-hooks--run-deploy-hooks 只会在 dry run 续签成功后调用 hook,并使用当前正在生效的证书,不会把 Let’s Encrypt staging 的测试证书交给 Nginx。
为什么会看到 ran with error output
如果 hook 中使用的是未加 -q 的 nginx -t,dry run 可能出现:
Hook 'deploy-hook' ran with error output:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful这通常不是失败。Nginx 会把 -t 的诊断信息,包括 syntax is ok 和 test is successful,写入标准错误流(stderr);Certbot 因此将这段内容标记为 error output。它表示“hook 向 stderr 写了内容”,不等于“hook 返回失败”。
判断时应注意:
test is successful表示 Nginx 配置检查成功。- 真正的 hook 失败通常还会出现
reported error code、test failed或 Nginx[emerg]信息。 - 本文脚本加了
nginx -t -q,可避免成功信息造成这种误解。
首次 dry run 显示 Account registered. 也属于正常现象:Certbot 可能正在 Let’s Encrypt staging 环境注册测试账户。Waiting 10 seconds for DNS changes to propagate 则是 Cloudflare 插件的默认 DNS 等待时间。
最终流程是:
Certbot 定时检查 → 证书进入续签窗口 → 续签成功
→ nginx -t -q 成功 → reload Nginx6. 安全删除证书(可选)
先查看证书的准确名称:
sudo certbot certificates删除前,必须确认 Nginx、Apache、Postfix 等服务已不再引用它。可先搜索相关路径,将 example.com 替换为 certbot certificates 显示的 Certificate Name:
sudo grep -R "live/example.com" /etc/nginx /etc/apache2 /etc/httpd /etc/postfix 2>/dev/null先移除或替换这些引用并验证相关服务,然后再让 Certbot 删除证书:
sudo certbot delete --cert-name example.com不要手工删除 /etc/letsencrypt/live、archive 或 renewal 内的文件。certbot delete 也不等于吊销证书;只有确实需要提前使证书失效时,才使用 certbot revoke。
如果这台服务器已不再有任何证书需要 Cloudflare Token,再到 Cloudflare 控制台撤销 Token,并删除本地凭据:
sudo rm /etc/letsencrypt/secrets/cloudflare.ini只有在没有任何 Certbot 证书供 Nginx 使用时,才删除全局 hook:
sudo rm /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh如果不再使用该 ACME 账户,可选择注销:
sudo certbot unregister