证书签发和续期
Verify error:acme.sh 域名验证失败的原因和修法
example.com:Verify error:Invalid response from http://example.com/.well-known/acme-challenge/...: 404Verify error 的意思是:CA 去验证你的域名,失败了;acme.sh 只是把 CA 的解释原样打印在冒号后面。 关键看这段解释:HTTP 状态码(404、403)、超时、NXDOMAIN、Incorrect TXT record,各自对应不同的修法。
快速修复
定位问题最快的办法是在测试环境加调试参数重跑一次,失败不占正式额度:
acme.sh --issue -d example.com -w /var/www/html --staging --debug 2
再按冒号后面的内容查对应原因:
Verify error: 后面的内容 |
最可能的原因 | 看第几节 |
|---|---|---|
Invalid response ...: 404 |
网站目录或 server 块不对 | 1 |
Invalid response ...: 403 |
拒绝规则、WAF、权限 | 2 |
Timeout during connect、Connection refused |
80 端口不通、IP 不对 | 3 |
Incorrect TXT record、NXDOMAIN looking up TXT |
DNS-01 记录查不到 | 4 |
CAA record ... prevents issuance |
CAA 没允许该 CA | 5 |
staging 上成功后,去掉 --staging,加一次 --force 正式签发。
原因
Verify error 有 5 类原因:HTTP-01 的 404、403 和连接问题,DNS-01 记录查不到,以及 CAA 等 CA 端拒绝。最常见的是网站目录不对导致的 404。
1. HTTP-01 网站目录不对(404)
acme.sh 把验证文件写到 <网站目录>/.well-known/acme-challenge/。如果 Web 服务器给这个域名用的是另一个目录,CA 就会拿到 404。
- 确认:
echo ok > /var/www/html/.well-known/acme-challenge/t后,curl http://example.com/.well-known/acme-challenge/t返回 404。 - 修复:
-w改成该 server 块实际使用的root(用nginx -T | grep root查);或者改用--nginx/--apache模式,让 acme.sh 临时改配置。反向代理站点要加一个location,让验证目录在本机直接返回。宝塔站点的根目录一般是/www/wwwroot/<域名>。
2. 被拒绝访问(403)
- 修复: 在禁止点开头文件的规则和 WAF 规则之前,给
/.well-known/acme-challenge/加例外,做法和 Certbot 403 unauthorized 完全一样。
3. 连接问题
- 修复: 每一层防火墙(云安全组、系统防火墙、宝塔防火墙)都放行 TCP 80,删掉残留的 AAAA 记录,关闭“禁止海外访问”之类的地域屏蔽,见 Timeout during connect。
--standalone模式需要 80 端口空闲,提示缺少socat时先安装它。
4. DNS-01 记录查不到
DNS API 把记录写到了错误的区域、API 密钥权限不够,或者 CA 在所有权威服务器同步前就开始验证。
- 确认: 运行过程中用
dig +short TXT _acme-challenge.example.com @权威服务器查不到,或者查到的是旧值。 - 修复: 检查 API 环境变量(DNSPod 用
DP_Id/DP_Key,阿里云解析用Ali_Key/Ali_Secret,Cloudflare 用CF_Token),确认域名的 NS 确实指向这家服务商;同步慢就加--dnssleep 120。用 CNAME 委托验证时加--challenge-alias。阿里云 RAM 子账号要授予云解析的管理权限。
5. CAA 等 CA 端拒绝
- 修复: 在 CAA 里加上 CA 的标识,比如
letsencrypt.org,ZeroSSL 以其官方文档给出的为准;见 CAA record prevents issuance。
各环境修法
各环境的共同原则:acme.sh 数据目录要持久保存,证书用 --install-cert 部署,同一个域名只交给一个客户端签发。
切换 CA:
acme.sh --set-default-ca --server letsencrypt
安装证书(让续期后的证书自动部署到 Web 服务器):
acme.sh --install-cert -d example.com \
--key-file /etc/nginx/ssl/example.com.key \
--fullchain-file /etc/nginx/ssl/example.com.pem \
--reloadcmd "systemctl reload nginx"
Docker(neilpang/acme.sh 镜像): 把 /acme.sh 数据目录挂成卷,账户和证书才能在重启后保留;否则每次运行都是新订单,容易触发速率限制。
通配符证书: 必须用 DNS-01(如 --dns dns_dp、--dns dns_ali),HTTP-01 无法验证 *.example.com。
升级: 老版本遇到 CA 接口变化会出各种错,先 acme.sh --upgrade。
宝塔面板: 宝塔的证书申请底层也是 ACME 客户端,面板里看到的“验证失败”提示和 Verify error 的后半句含义相同。面板申请和命令行 acme.sh 不要同时给同一个域名签发,否则两边互相覆盖证书文件,续期时间也会错乱。
不要这样做
下面 3 种做法会耗光签发额度、泄露密钥,或者让服务器失去防护。
- 在定时任务里保留
--force。 每次都不管是否快到期就续,额度很快耗光。 - 把
--debug日志原样贴到论坛、群里。 里面有 API 密钥和账户地址。 - 为了验证通过把防火墙或 WAF 全关掉。 只放行验证路径,或者改用 DNS-01。
常见问题
acme.sh 现在默认用的是哪家 CA?
从 3.0 版开始默认是 ZeroSSL,需要先用邮箱注册账户(acme.sh --register-account -m you@example.com)。执行 acme.sh --set-default-ca --server letsencrypt 改用 Let's Encrypt,或者每条命令加 --server letsencrypt。
怎么看到完整的请求和响应?
命令后面加 --debug 2(更详细用 --debug 3)。输出在终端里,开启日志时也会写进 ~/.acme.sh/acme.sh.log。发给别人看之前,先删掉里面的 API 密钥。
国内服务器装 acme.sh 很慢或者装不上怎么办?
从 acme.sh 在 Gitee 上的镜像仓库克隆后本地安装。官方安装脚本要从 GitHub 下载,国内网络可能很慢;安装后用 acme.sh --upgrade 保持更新。注意只从官方仓库或其官方镜像获取,不要用来路不明的修改版。
反复重试有什么影响?
每次验证失败都会计入 CA 的限制,Let's Encrypt 是每账户每标识符每小时最多 5 次。先用 --staging 调通,再去掉它并加一次 --force,替换掉测试证书。