ACME 客户端与自动化

Certbot 用 Cloudflare DNS 插件申请通配符证书

作者: · 最后核实

Certbot 申请通配符证书要用 certbot-dns-cloudflare 插件:插件用 Cloudflare API Token 添加 _acme-challenge TXT 记录完成 DNS-01 验证,为 example.com 和 *.example.com 签发 Let's Encrypt 证书,续期和重载都自动完成。

适用于用 snap(或 pip)安装 Certbot 4.1 及以上、DNS 托管在 Cloudflare 的 Linux 服务器。

前提条件

DNS-01 不需要开放入站端口,80 端口不通、未备案的服务器也能签发,有该域名的 Cloudflare API Token 就够了。

  • 带 systemd 和 snapd 的 Linux 服务器,有 sudo 权限。
  • 域名的 NS 已经切到 Cloudflare(控制台显示 Active)。
  • 在 My Profile → API Tokens 创建 Token,权限选 Zone → DNS → Edit,范围只选 example.com。
  • 服务器能访问 Let's Encrypt 和 api.cloudflare.com。

第一步:安装 Certbot 和 Cloudflare 插件

snap 版 Certbot 要先允许插件以 root 运行,再安装 certbot-dns-cloudflare:

sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare
certbot plugins | grep -A1 dns-cloudflare

用 pip 装在 /opt/certbot 的,改为运行 sudo /opt/certbot/bin/pip install certbot-dns-cloudflare。

第二步:把 Token 写进凭据文件

插件从凭据文件读取 Token,这个文件只能让 root 读取:

sudo mkdir -p /root/.secrets/certbot
sudo tee /root/.secrets/certbot/cloudflare.ini > /dev/null <<'EOF'
dns_cloudflare_api_token = your-cloudflare-api-token
EOF
sudo chmod 600 /root/.secrets/certbot/cloudflare.ini

文件能被其他用户读取时 Certbot 会报警。

第三步:签发通配符证书

certonly 只申请证书、不改 Web 服务器配置,主域名和通配符写在同一条命令里:

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/certbot/cloudflare.ini \
  -d example.com -d '*.example.com'

'*.example.com' 要加引号防止被 Shell 展开。必须同时写 example.com,通配符不包含主域名。证书保存在 /etc/letsencrypt/live/example.com/。

第四步:使用证书并添加重载钩子

Web 服务器引用 fullchain.pem 和 privkey.pem,以 Nginx 为例:

ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

certonly 不会改服务器配置,需要加部署钩子让续期后自动重载:

sudo certbot reconfigure --cert-name example.com --deploy-hook "systemctl reload nginx"

也可以在签发命令里加 -i nginx,让 Nginx 安装器自动修改配置并重载。

验证

签发成功后,主域名和任意子域名都返回同一张 Let's Encrypt 证书。用 SSL 证书检查 检查主域名和子域名,或在终端运行:

curl ssl.sh/example.com
curl ssl.sh/api.example.com

在服务器上:

sudo certbot certificates
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -ext subjectAltName

自动续期

插件名、凭据路径和等待时间都保存在 /etc/letsencrypt/renewal/example.com.conf,snap 定时器每天两次按需续期,Certbot 4.1 及以上会按 ARI 建议时间续期。测试:

sudo certbot renew --dry-run
systemctl list-timers | grep certbot

Token 失效会导致续期失败:轮换或删除 Token 后要同步更新凭据文件。Let's Encrypt 不再发到期提醒邮件,建议把域名加到 ssl.sh 监控(开发中)。钩子的更多用法见 Certbot 续期钩子。

常见问题排查

  • Error determining zone_id 或 9109: Invalid access token:Token 错误、过期或没有这个域名的权限,重新创建 Zone → DNS → Edit 的 Token。
  • Unsafe permissions on credentials configuration file:对 ini 文件执行 sudo chmod 600。
  • DNS problem: NXDOMAIN looking up TXT:记录还没生效,加 --dns-cloudflare-propagation-seconds 60。
  • CAA record prevents issuance:CAA 记录没有 letsencrypt.org,或 issuewild 排除了它,见 CAA 记录阻止签发。
  • too many certificates already issued:测试时用 --dry-run 或 --test-cert,见 Let's Encrypt 频率限制。
  • 二级子域名提示证书不匹配:a.b.example.com 不在 *.example.com 范围内,见 NET::ERR_CERT_COMMON_NAME_INVALID。

常见问题

需要关闭 Cloudflare 代理(橙色云朵)吗?

不需要。DNS-01 只检查 TXT 记录,A/AAAA 记录是否走代理无关。只有用 HTTP-01 而 Cloudflare 无法把验证请求转到源站时才需要关代理。

域名在阿里云 DNS 或 DNSPod,有 Certbot 插件吗?

没有官方插件。Certbot 官方维护的 DNS 插件里没有阿里云和 DNSPod,社区插件质量参差不齐。国内 DNS 推荐用 acme.sh,内置 dns_ali 和 dns_tencent,见 acme.sh + 阿里云 DNS/DNSPod。

propagation-seconds 设多少合适?

插件默认等 10 秒,Cloudflare 通常够用。验证时报找不到 TXT 记录,就加 --dns-cloudflare-propagation-seconds 60 重试,这个值会保存下来供续期使用。

资料来源

  1. certbot-dns-cloudflare documentation
  2. Certbot instructions (snap)
  3. Certbot User Guide
  4. Let's Encrypt: Challenge Types