Hi @LotusJeff,
是的,DNS 验证仍然可用,但请不要再使用我第一篇文章中的模板。它与当前的 discourse_docker 已经不同步:
- 其中的
cert_exists检查在当前 Let’s Encrypt 证书链下会失败,导致每次容器启动时都会强制生成新证书,可能会触发重复证书的频率限制。 - 其中的 nginx
replace步骤针对的行已经移动,而add_header步骤现在会覆盖一个无关的ETag标头。
你现在不再需要自定义模板。保留官方的 Let’s Encrypt 模板,并在 app.yml 中将其切换为 DNS 验证:
templates:
# ...
- "templates/web.ssl.template.yml"
- "templates/web.letsencrypt.ssl.template.yml"
env:
# ...
CF_Token: "YOUR_TOKEN" # 具有此区域 Zone > DNS > Edit 权限的 Cloudflare API 令牌
CF_Zone_ID: "YOUR_ZONE_ID"
run:
- exec:
cmd:
- mkdir -p /opt/dnsapi
- curl -fsSL https://raw.githubusercontent.com/acmesh-official/acme.sh/3.0.6/dnsapi/dns_cf.sh -o /opt/dnsapi/dns_cf.sh
- replace:
filename: /usr/local/bin/letsencrypt
from: "-w /var/www/discourse/public"
to: "--dns dns_cf"
此配置的作用:
- 官方模板仅下载主要的
acme.sh脚本,不包含 DNS 插件。exec步骤添加了 Cloudflare 插件,官方启动脚本会将其复制到/shared/letsencrypt/dnsapi/。请保持 URL 中的版本与templates/web.letsencrypt.ssl.template.yml中的 acme.sh 版本一致(目前是 3.0.6)。 run:部分在模板之后运行,因此replace步骤将官方启动脚本从 HTTP 验证切换为 DNS 验证。- acme.sh 在验证期间从环境中读取
CF_Token和CF_Zone_ID,并将它们与证书一起保存。每日 cron 作业无法看到容器环境,因此续期操作会使用保存的副本。
如果你使用了我的旧模板,请从 templates: 中移除相关行,并将 LETSENCRYPT_CF_TOKEN 和 LETSENCRYPT_CF_ZONE_ID 重命名为 CF_Token 和 CF_Zone_ID。
如果你已经拥有证书(来自 HTTP 验证或我的旧模板),请在重建之前将旧的 acme.sh 文件夹移至别处:
cd /var/discourse
mv shared/standalone/letsencrypt shared/standalone/letsencrypt.old
./launcher rebuild app
如果不这样做,acme.sh 可能会跳过 DNS 步骤(它会保留旧方法直到需要续期,且 Let’s Encrypt 可以复用近期的验证记录)。结果导致令牌永远不会被保存,且第一次 cron 续期会失败。使用全新的文件夹后,acme.sh 将注册一个新账户并执行真正的 DNS 验证,因此首次启动大约会多花一分钟。
在新证书正常工作之前,请保留 .old 文件夹。如果 DNS 步骤失败,启动脚本仍会覆盖 shared/ssl 中的文件,nginx 将无法启动。
acme.sh 以纯文本形式将令牌存储在 shared/standalone/letsencrypt/ 下,因此请仅授予令牌所需的权限。
截至 2026 年 11 月,已在 discourse_docker 和 Discourse latest 版本上测试通过。