声明
本文由 🤖AI 协作完成.
2026-09-20 实测记录。目标:本地 macOS 得到一个编译了
dns.providers.alidns的 Caddy,
用于验证泛域名证书的 ACME DNS-01 签发路线(与自产 CA 的tls internal互为备选)。
1. 背景
- Caddy 内置 ACME 客户端,但 DNS provider 一律是第三方 Go module,官方标准镜像/Homebrew 二进制里都没有。
/docs/modules/官网文档页只描述”如果装了它配置长什么样”,不代表已内置;判定标准是caddy list-modules。- 插件必须编译进二进制,两种方式:
- caddyserver.com/download 在线勾选插件定制下载;
- 本地
xcaddy构建(本文采用,适合反复迭代)。
相关文档:
- 官方 Wiki(权威指南):https://caddy.community/t/how-to-use-dns-provider-modules-in-caddy-2/8148
- alidns 插件仓库:https://github.com/caddy-dns/alidns
- Docker 定制构建:https://hub.docker.com/_/caddy 的 “Adding custom Caddy modules” 一节
2. 构建
1 | # 1. 工具链(一次性) |
产物为当前目录下的 caddy 二进制。
3. 安装与验证
1 | # 验证插件已编入 |
注意:这是手动二进制,没有服务管理器托管,不会开机自启;临时验证够用,
需要常驻时自行配 LaunchAgent。
4. 本地测试配置
测试 Caddyfile 就一个文件:~/.config/Caddyfile(凭证走环境变量,跑之前 export 两个变量即可):
1 | { |
Tip
可以通过本地 hosts 添加解析记录: 127.0.0.1 debug.nnsay.cn 来测试
1 | export ALIYUN_ACCESS_KEY_ID=... ALIYUN_ACCESS_KEY_SECRET=... |
启动后观察日志:Caddy 会调用 alidns API 写一条 _acme-challenge TXT 记录,
签发成功则证书落盘到本地存储目录,随后泛域名站点可用 HTTPS 访问。
alidns 凭证建议用只授 DNS 权限的 RAM 子账号 AK(详见 https://github.com/libdns/alidns )。
注:
--envfile传环境文件也行(Caddy 不会自动加载.env);凭证同样可以直接
写进 Caddyfile,本地测试图省事可接受,交付配置仍建议环境变量。
5. 验证结果(2026-09-20 实测通过)
5.1. 成功日志的关键节点
1 | http.acme_client trying to solve challenge {"challenge_type": "dns-01", ...} |
got renewal info 日志会给出下次续期窗口(到期前 2/3 生命周期内随机挑时间),
DNS-01 续期同样全自动(重写 TXT → 验证 → 换证),无需人工干预。
5.2. 端到端验证
不动 /etc/hosts 的话,用 --resolve 模拟解析(效果等价):
1 | curl -s --resolve debug.nnsay.cn:443:127.0.0.1 https://debug.nnsay.cn/ |
curl 未带 -k、未配置任何 CA——原生信任通过,验证了”客户端零导入”这条路线特征。
6. Docker 部署等价方案
交付/服务器侧用官方 builder 镜像多阶段构建(compose 从 image: 改 build:):
1 | FROM docker.m.daocloud.io/library/caddy:2-builder AS builder |
容器内凭证通过 compose environment: 注入。
7. 路线对比(何时选 alidns,何时选 tls internal)
自产 CA(tls internal) |
ACME + alidns(DNS-01) | |
|---|---|---|
| 外网依赖 | 无(零依赖交付) | 需要(DNS API 可达) |
| 客户端 | 需导入 root 证书 | 零导入 |
| 每客户隔离 | 重跑 scripts/gen-ca.sh |
需各自域名 |
| 适用 | 私有化交付兜底 | 有网客户,浏览器/工具开箱即信 |
两条路线可在同一 Caddyfile 内按站点共存。
8. QA(踩坑排查)
8.1. fork/exec ./caddy: permission denied
go build -o 指向已存在的目录时,二进制会写进该目录内部,而不是覆盖为该路径。
若在 tmp/caddy/ 目录上执行 build,产物实际是 tmp/caddy/caddy,
shell 里 ./caddy 解析到目录本身,就会报 fork/exec: permission denied。
解决:build 在一个不含同名文件/目录的空目录里进行;或执行 tmp/caddy/caddy。
可用 file ./caddy 判断——输出 directory 说明执行的是目录。
8.2. cannot found specified zone:nnsay.cn(AppendRecords 失败)
alidns API 报 cannot found specified zone:AK 所属的阿里云账号在
「云解析 DNS」域名列表里看不到该域名。与 Caddyfile 语法无关,LE/ZeroSSL
两个 CA 都会在同一步失败(瓶颈在 DNS API 这头)。
解决:换用解析所在账号的 AK;若账号一致,给 RAM 用户授 AliyunDNSFullAccess。
排查入口:阿里云控制台 → 云解析 DNS → 域名列表,确认域名在当前 AK 的账号名下。