出现 DNS 验证失败且伴随 unauthorized 报错,绝大多数情况是 DNS 服务商的 API 密钥配置错误或权限不足,而非 Let's Encrypt 服务端问题,建议优先检查 DNS 提供商后台的 API 令牌权限。
先说结论:该错误通常意味着 ACME 客户端无法通过 DNS 服务商的 API 接口写入验证记录,需重点排查密钥有效性与账户权限。
- 先确认:API Key 和 Secret 是否复制完整,是否存在多余空格或换行。
- 先处理:登录 DNS 服务商后台,确认该密钥已授予 DNS 记录编辑(DNS Edit/Write)权限。
- 再验证:使用客户端的调试模式(如
`--debug`)重新运行续签命令,观察 API 调用返回的具体 HTTP 状态码。
命令速用版
以下命令用于快速检查 DNS 解析状态及客户端调试,需在服务器终端执行:
dig TXT _acme-challenge.yourdomain.com:检查验证记录是否已生成。
export CF_Key="your_api_key" && export CF_Email="your_email":配置 Cloudflare 环境变量(以 acme.sh 为例)。
acme.sh `--issue` `--dns` dns_cf -d yourdomain.com `--debug`:使用 acme.sh 指定 Cloudflare 插件调试。
certbot renew `--dry-run` `--verbose` `--dns-cloudflare`:使用 Certbot 模拟续签并输出详细日志。
为什么会这样
Let's Encrypt 的 DNS-01 验证机制要求客户端通过 API 自动在您的域名解析记录中添加一条 TXT 记录。当客户端向 DNS 服务商(如阿里云、Cloudflare、DNSPod 等)发起 API 请求时,如果提供的密钥无效、过期,或者该密钥没有被授予“修改 DNS 记录”的权限,服务商就会返回 401 Unauthorized 或 403 Forbidden 错误。这与服务器本身的 80 端口无关,纯粹是客户端与 DNS 服务商之间的身份认证失败。
分步处理
1. 检查 API 密钥配置
登录您的 DNS 服务商控制台,找到 API 密钥管理页面。确认使用的 Key 和 Secret 是否正确。部分服务商(如 DNSPod)需要区分登录密码和 API 专用密钥,必须使用后者。确保环境变量或配置文件中没有多余的空格。
2. 验证账户权限(主流服务商示例)
检查该 API 密钥绑定的权限策略,不同服务商配置路径如下:
- 阿里云:RAM 访问控制 -> 权限策略 -> 授予
AliyunDNSFullAccess或自定义包含DescribeDomainRecords和UpdateDomainRecords的策略。 - Cloudflare:My Profile -> API Tokens -> 创建令牌 -> 权限区域选择
Zone:DNS:Edit。 - 腾讯云:访问管理 -> API 密钥管理 -> 确保密钥状态为“启用”,子用户需授予
DNSPodFullAccess。
3. 清理客户端缓存配置
如果之前更换过密钥,客户端可能缓存了旧配置。对于 acme.sh,检查 ~/.acme.sh/account.conf;对于 Certbot,检查插件配置文件。必要时删除旧配置重新初始化。
4. 确认域名托管状态
确保申请证书的域名确实托管在当前配置 API 密钥的 DNS 服务商账户下。如果域名已转移但未更新客户端配置,API 请求会因找不到域名而失败。
怎么验证是否生效
执行续签命令后,观察日志输出。成功的标志是客户端提示"Verification successful"或"Certificate renewed"。您也可以使用 openssl s_client -connect yourdomain.com:443 查看当前生效证书的过期时间,确认是否已更新为新证书。此外,登录 DNS 服务商后台,查看是否在续签过程中产生了新的 TXT 记录并随后被自动清除。
常见坑
1. 密钥类型混淆:部分平台(如 Joker DNS)的 API 密钥与登录密码不同,需在特定页面生成,直接使用登录密码会导致认证失败。
2. DNS 传播延迟:虽然 DNS 验证通常很快,但在某些网络环境下,Let's Encrypt 服务器可能无法立即读取到新添加的 TXT 记录,导致超时而非 unauthorized,但需区分两者。
3. 频率限制:如果短时间内频繁重试,DNS 服务商或 Let's Encrypt 可能触发速率限制,此时错误信息可能变为 429 Too Many Requests,需等待一段时间再试。
4. 配置文件权限:存储 API 密钥的配置文件(如 acme.json)权限设置过宽可能导致客户端拒绝读取,确保文件权限为 600。