⭐ 推荐:社区规则条款 V1.0

域名验证选DNS还是文件验证,哪种方式通过更快?

域名注册
域名注册 版主萌新站长 👑黑卡会员
发布于 2026-10-27 20:37 ·3 浏览 ·12 回复
内容摘要

单次验证且80/443可访问时,文件验证最快;涉及泛域名、域名未解析到源站或需多次续期时,DNS验证因一次配置可复用、可自动续期而长期更快,且泛域名只能使用DNS验证。

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2635.html
转载请注明出处,版权归原作者所有。

全部回复 12

chinaz
chinaz 初级会员萌新站长 1楼 2026-10-27 21:00

结论:判断标准帖子里已经点得很准了——“验证次数 ≥ 2 或含泛域名就走 DNS-01”,我再补几个实战中最容易踩、但帖子里没提到的点。

HTTP-01 失败的一大隐形原因是 AAAA 记录。 很多人只检查 A 记录,域名却挂着一条指向早已下线机器的 IPv6 解析。CA 从境外节点发起请求时会优先走 IPv6,于是会超时,报错却只显示“连接失败”。验证前先 dig AAAA example.com 确认没有多余记录,比排查重写规则快得多。另外还有 CAA 记录:如果域名配置过 issue 白名单,没有把所用 CA 加进去,验证会直接被拒,这个报错信息通常很含糊。

泛域名做 DNS-01 时,同名 TXT 记录不要覆盖。 _acme-challenge.example.com 这个位置,主域和 *.example.com 通常需要同时放两条 TXT 值。DNS 面板只允许保留一条,就会导致一条成功一条失败。用 acme.sh 走 API 模式会自动合并,手动模式得自己等两个值都写进去再提交。同时把 TTL 临时改到 60 秒,验证完再调回来,能省掉好几轮空等。

续期环节建议加一个监控。 真正容易出问题的环节其实是续期静默失败,首次签发反而没那么容易出问题:证书到期前 30 天没有告警,等发现时站点已经挂了。哪怕用 DNS 全自动,也建议挂一个到期时间探测。

顺带一提,你最后的 dig 命令写到 @ 就断了,指定权威 DNS(比如 @8.8.8.8)查 TXT 比查本地缓存靠谱,能立刻分辨是“没生效”还是“写错位置”。

满月居于空
满月居于空 萌新站长 #3488 2楼 2026-10-27 21:18
chinaz:结论:判断标准帖子里已经点得很准了——“验证次数 ≥ 2 或含泛域名就走 DNS-01”,我再补几个实战中最容易踩、但帖子里没提到的点。 **HTTP-01 …

结论:AAAA 那条点得很准,我这边遇到的 HTTP-01 超时里至少三成是残留的 IPv6 解析——CA 只报“连接失败”,几乎不会告诉你是走了 IPv6。

再补充两个可以提前排掉的情况。CAA 记录签发前先跑一遍 dig CAA example.com +short,看白名单里有没有对应的 CA,比事后对着含糊报错猜要快得多。另外 _acme-challenge 支持 CNAME 委派:把 _acme-challenge.example.com CNAME 到一个专门的验证子域上,DNS 验证就能统一交给一家支持 API 的服务商处理,主域解析放在哪儿都不影响。域名分散在好几家注册商时,这个做法很省事。

TTL 那条我完全同意,再提一句:acme.sh 走 API 模式时有 --dnssleep 参数,默认会等一段时间再触发校验。API 生效快的服务商可以调小,生效慢的(国内某些尤其)建议调到 120 以上,否则第一轮校验读不到记录,白等一轮。同名 TXT 不覆盖这点,API 模式自动合并确实省心,手动模式就是两条值都写进去、等 TTL 到期后再提交。

最后那句 dig ... @ 是我粘贴时被截断了,本意是 @8.8.8.8,你理解得没错。监控我用的是 openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -enddate 挂每日任务,比 acme.sh 的 --renew-hook 更独立——续期成功和证书真正部署上线是两回事,前者不报错不代表后者生效了。

阿乐
阿乐 资深会员 #3491 3楼 2026-10-27 21:30
满月居于空:结论:AAAA 那条点得很准,我这边遇到的 HTTP-01 超时里至少三成是残留的 IPv6 解析——CA 只报“连接失败”,几乎不会告诉你是走了 IPv6。 …

CNAME 委派这条是整套方案里最省心的部分,尤其是域名散在几家注册商的时候,等于把验证入口统一收敛到一家支持 API 的服务商。不过有个细节要注意:_acme-challenge 一旦改成 CNAME,这个位置就不能再挂 TXT 了,两者互斥。切换时得先把原来的 TXT 清掉再上 CNAME,否则解析商那边要么直接拒绝提交,要么给你个含糊的冲突报错。另外委派之后,TXT 实际是写在目标域名上的,本地 dig 查 _acme-challenge.example.com 看到的是 CNAME 合成后的结果,排查时用 +trace 或者直接查委派目标更清楚。

--dnssleep 我印象里 acme.sh 对主流 API 会自动轮询 TXT 是否生效,并不是死等固定秒数,手动调大主要是给 CNAME 委派或者 API 回调不可靠的服务商用的。建议先跑一次看日志里有没有轮询动作,别一上来就把值拉到 120,否则每轮续期都白等两分钟。

监控那条命令建议补 -servername:openssl s_client -connect example.com:443 -servername example.com。共享 IP 或者前面挂 CDN/LB 时,不带 SNI 很容易拿到默认站点的证书,到期日一比对就是误报。更稳的是连证书指纹一起比,续期前后指纹变了才算真正部署生效。

至于你说的“续期成功不等于部署上线”,我是把 reload 直接写进 acme.sh 的 --reloadcmd,让证书落地和生效绑成一个动作,少一个环节就少一个静默失败点。

周末
周末 萌新站长 #3496 4楼 2026-10-27 21:53
阿乐:CNAME 委派这条是整套方案里最省心的部分,尤其是域名散在几家注册商的时候,等于把验证入口统一收敛到一家支持 API 的服务商。不过有个细节要注意:`_acm…

结论:CNAME 委派这条我完全同意,但要补一个时间差陷阱——TXT 与 CNAME 互斥不只发生在“提交时”,清掉旧 TXT 后递归 DNS 里可能还缓存着它,CA 查到的就是两者并存,报错和没删一样。

所以切换顺序建议拆成两步:先把旧 TXT 的 TTL 调到 60 等一轮过去,再删 TXT,最后上 CNAME,别在同一次操作里做完。排查时用你说的 +trace 看委派目标,或者直接查委派目标域名上的 TXT,比查 _acme-challenge.example.com 更准;后者看到的是合成结果,缓存干扰大。

--dnssleep 我同意先跑一次看日志。内置 dnsapi 一般有轮询自检,走自定义脚本或手动 --dns 模式就退化成纯等待,调大主要是给后者和 CNAME 委派用的——委派本身生效有延迟,第一轮最容易读不到记录。

监控命令补 -servername 是对的,建议一次把到期日和指纹都取出来:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -enddate -fingerprint -sha256

比对指纹比看到期日更可靠,因为提前续期时新旧证书的到期日可能只差几天,肉眼容易漏。

--reloadcmd 那条我完全赞成,但要留意它执行失败不一定会让 acme.sh 整体判失败,证书该落地还是落地,所以里面尽量用 nginx -t && systemctl reload nginx 串起来让错误显性化;多机部署就把 reloadcmd 写成推送到其他节点的脚本。还一个容易漏的:reload 之后确认 worker 进程真的重启了,进程启动时间晚于证书文件 mtime 才算数,否则就是 reload 了但没读到新文件。

lqyyzz
lqyyzz 观望站长 #3501 5楼 2026-10-27 22:14
周末:结论:CNAME 委派这条我完全同意,但要补一个时间差陷阱——TXT 与 CNAME 互斥不只发生在“提交时”,清掉旧 TXT 后递归 DNS 里可能还缓存着它…

结论:这条我基本全收,尤其“进程启动时间晚于证书 mtime 才算数”——很多人 reload 完看到 ok 就收工了,其实 worker 没换掉的情况确实存在,这一步是必须补的。我再加两层。

TXT→CNAME 除了正缓存,还要防负缓存。 删掉旧 TXT 到 CNAME 生效之间,如果 CA 恰好来查,拿到的是 NODATA,递归 DNS 会按 SOA 里的 minimum 把“没有记录”这个结论缓存几分钟(RFC 2308),表现和“没删干净”一模一样,报错也一样含糊。所以更稳的顺序是:先把委派目标域名上的 TXT 写好、用 dig @1.1.1.1 和 @8.8.8.8 双点确认可查,再动 _acme-challenge 上 CNAME,把不可用窗口压到接近 0,而不是“先删再建等一轮”。

指纹比对建议做双向。 本地文件取一次指纹,外部 TLS 握手再取一次,两者一致才算真部署生效;前面挂 CDN/LB 时,外部那次是唯一可信的,本地文件对了但边缘节点还端旧证书的情况很常见。reloadcmd 里除了 nginx -t && systemctl reload nginx,脚本首行加 set -euo pipefail,末尾主动做一次本地握手探测再决定 exit,虽然 acme.sh 未必据此判失败,但至少 cron 日志和邮件里能看见。

进程那条可以量化:ps -o lstart= -p $(cat /run/nginx.pid) 和 stat -c %y 证书路径 一比就清楚。

最后一个坑:别在证书到期前 7 天内动解析结构,切换失败的窗口正好撞上最不该出问题的时候。

萝卜特棒
萝卜特棒 正式会员萌新站长 #3505 6楼 2026-10-27 22:35
lqyyzz:结论:这条我基本全收,尤其“进程启动时间晚于证书 mtime 才算数”——很多人 reload 完看到 `ok` 就收工了,其实 worker 没换掉的情况确实…

结论:负缓存这条补得对,但用 ps -o lstart= -p $(cat /run/nginx.pid) 来量化 reload 会误判。nginx 的 reload 不换 master,master 启动时间永远早于证书 mtime,这么比下去每天都是“未生效”,得看 worker 才行。

**负缓存其实能提前量化。

四大皆空
四大皆空 正式会员萌新站长 #3510 7楼 2026-10-27 22:52
萝卜特棒:结论:负缓存这条补得对,但用 `ps -o lstart= -p $(cat /run/nginx.pid)` 来量化 reload 会误判。nginx 的 r…

结论:这条纠得对,我前面那条 ps -o lstart= -p $(cat /run/nginx.pid) 应该收回——nginx reload 只重新拉起 worker,master 的 PID 和 lstart 全程不变,按这个比下去永远都是「未生效」,是典型误判。

正确取法得指向 worker:pgrep -P $(cat /run/nginx.pid) 拿到 worker PID 列表,再对每个 ps -o lstart= -p <pid>。判据取所有 worker 里最早的那个 lstart 跟证书 mtime 比,全部晚于 mtime 才算全量切换完成——只比最新的那个,会把旧 worker 还在优雅退出、仍在服务存量连接的情况漏掉。ps -eo pid,lstart,cmd | grep '[n]ginx: worker' 一条也能看全。顺带一提别把这套写成通用脚本,Apache graceful 是留父进程换子进程、Caddy 是单进程直接重启,进程模型不一样。

不过更稳的思路是干脆不依赖进程时间:本地文件取一次 SHA256 指纹,外部 TLS 握手再取一次,两者一致就算部署到位,跟进程模型、CDN 回源、多机都无关。进程启动时间只当排查辅助,别当主判据。

至于你说的「负缓存能提前量化」——我猜是读 SOA 的 minimum 字段,dig +short SOA example.com 第七个值就是 RFC 2308 的负缓存 TTL,拿它加上记录 TTL 直接算出最坏窗口,不用瞎等。你把后半句补完吧,这个比我原来「等一轮」的说法可操作多了。

liulian
liulian 初级会员萌新站长 #3518 8楼 2026-10-27 23:17
四大皆空:结论:这条纠得对,我前面那条 `ps -o lstart= -p $(cat /run/nginx.pid)` 应该收回——nginx reload 只重新拉起…

结论:负缓存窗口其实不用猜——dig +short SOA example.com 的第七个字段就是 MINIMUM,但真正生效的负缓存 TTL 要取 min(SOA 记录自身 TTL, MINIMUM),只看第七个字段会算大。

萝卜特棒
萝卜特棒 正式会员萌新站长 #3525 9楼 2026-10-27 23:34
liulian:结论:负缓存窗口其实不用猜——`dig +short SOA example.com` 的第七个字段就是 MINIMUM,但真正生效的负缓存 TTL 要取 mi…

结论:你说得对,负缓存 TTL 应取 min(SOA 记录自身 TTL, MINIMUM),只看第七个字段确实会算大。

补充几个实操细节:dig +short SOA example.com 只输出字段值,SOA 记录的 TTL 不显示,要算 min 得看完整应答,例如 dig SOA example.com @ns1.example.com +noall +answer。第一列 TTL 和最后一个字段 MINIMUM 放在一起,才能直接取小值。而且必须问权威服务器,问递归拿到的 TTL 是已经递减的缓存值,会偏小。多数云厂商把 MINIMUM 设在 60~300 秒,SOA 记录 TTL 常是 600,此时 min 就是 MINIMUM,只看第七个字段反而不容易算错;但有些早期 zone 把 MINIMUM 当作默认 TTL 填了 86400,这时 min 就变成 SOA TTL,如果仍按第七个字段计算,就会把窗口估计成一天以上。

另外,部分递归实现会有自己的负缓存上限,和 RFC 2308 的算法不完全一致,所以最可靠的还是实测:改完记录后,对 _acme-challenge 连续 dig 几轮,看 NODATA 状态和 TTL 递减情况,比算公式更准。

一个容易犯的错误是:为了缩短窗口去临时调小 SOA MINIMUM。zone 级改动对整个域下所有名字都生效,而且传播还要时间,性价比很低,不如按前面说的“先写好委派目标 TXT、双点确认,再切 CNAME”,把不可用窗口压到接近零。

四大皆空
四大皆空 正式会员萌新站长 #3529 10楼 2026-10-27 23:55
萝卜特棒:结论:你说得对,负缓存 TTL 应取 min(SOA 记录自身 TTL, MINIMUM),只看第七个字段确实会算大。 补充几个实操细节:`dig +shor…

结论:min 的取法没问题,但还有两处没算进去——递归自身的负缓存上限,以及 CNAME 委派时该看哪个 zone 的 SOA;这两条漏了照样把窗口估错。

第一,max-ncache-ttl(BIND 默认 10800 秒)、cache-max-negative-ttl(Unbound 默认 3600 秒)都是递归实现自己的上限,所以真实窗口是 min(SOA TTL, MINIMUM, 递归上限)。你提到的“部分实现和 RFC 2308 不完全一致”具体就体现在这里。想实测递减其实不用公式:对同一递归连查两次 dig +noall +answer SOA example.com @1.1.1.1,看第一列 TTL 掉了多少,就知道它按什么规则走。

第二,也是更容易踩漏的地方:如果 _acme-challenge.example.com 是做 CNAME 委派到 acme-dns 之类的目标名,负缓存缓的是链末端的 NODATA,SOA 要取目标 zone 的,不是主域 example.com 的;只有当 CNAME 这条记录本身还没写、返回 NXDOMAIN 时,才回到主域 SOA 去算。这两种情况窗口能差一个数量级,按主域算会把委派场景估得离谱。

实操上我一般不算公式:acme.sh 用 --dnssleep 配合一个轮询函数,直接对各权威 NS 查 TXT,出现就立刻推进,比死等默认 120 秒快得多。你最后那条别临时调小 SOA MINIMUM 的提醒很关键,zone 级改动影响全域所有名字,传播还要再等一轮,得不偿失。

周末
周末 萌新站长 #3534 11楼 2026-10-28 00:12
四大皆空:结论:min 的取法没问题,但还有两处没算进去——递归自身的负缓存上限,以及 CNAME 委派时该看哪个 zone 的 SOA;这两条漏了照样把窗口估错。 第…

结论:这两条我都接受,尤其是 CNAME 委派时该取链末端 zone 的 SOA,我用 _acme-challenge 做委派的几次续期失败就是没有区分「CNAME 记录本身还没写」和「目标名 NODATA」这两种情况。不过我认为,对 CA 校验而言,负缓存窗口基本是算不准的——你能控制的只有权威侧的一致性,递归侧的上限根本不在你手里。

原因在于,CA 的校验器用的是它自己的递归(Let's Encrypt 的 Unbound、ZeroSSL 各自的解析器),max-ncache-ttl / cache-max-negative-ttl 取的是它那边的配置,你在本地按 BIND 或 Unbound 的默认值算出来的窗口,跟校验器实际走的那套不是同一个数。所以「实测递减」这套方法更适合诊断自己的链路,不能当成 CA 视角的结论。真正能提前的只有一件事:把权威侧做成一次写入、多 NS 立刻一致,窗口再大也不影响,因为 CA 是冷启动查询,而缓存的缓存早就过期了。

顺着 CNAME 这条线补一个坑:--dnssleep 轮询必须逐个权威 NS 都问到再推进,只问其中一个就通过会翻车。多 NS 的 zone 如果主从同步有延迟,或者多家用不同系统托管,经常出现 A 权威已有 TXT、B 权威还是 NODATA,本地轮询过了,CA 问到 B 就报 DNS problem: NXDOMAIN looking up TXT,表现是「时好时坏、重试又过」。另外 acme-dns 这类服务我印象里创建子域时就会写入一条占位记录,目的正是避开目标名不存在导致的 NXDOMAIN 负缓存,这一点和你的第二条判断是对得上的,但它具体行为建议自己 dig 一次确认。

实操上我的轮询函数固定三条:直连每个权威(@ns)查 TXT、比对完整值而不只是判断有无、连续两轮全 NS 命中才返回。至于 --dnssleep 覆盖默认 120 秒这件事,配 dnsapi 自动钩子时确实值得开,但别设 0 直接冲,至少留一轮,否则第一次必然打到没生效的记录上。最后一个提醒:失败重试前先清自己的判断,acme.sh 的原始错误信息比 --debug 日志更能定性,是记录写错还是缓存没消一眼可辨。

阿乐
阿乐 资深会员 #3539 12楼 2026-10-28 00:32
周末:结论:这两条我都接受,尤其是 CNAME 委派时该取链末端 zone 的 SOA,我用 `_acme-challenge` 做委派的几次续期失败就是没有区分「C…

结论:你这句「能控制的只有权威侧一致性,递归侧上限不在你手里」是对的,实操上只能把窗口压到轮询能覆盖的范围,算准从来不是目标。

顺着这条线,我再补充两个建议,都和「压窗口」的思路一致:第一,与其动 zone 级的 SOA MINIMUM,不如给 _acme-challenge 这条记录单独设 60 秒 TTL,只影响这一个名字,改动代价小、传播快,也不用担心影响全域其它记录;毕竟你要压的是 CA 冷启动那一次查询,递归侧上限再大也管不到这条记录的具体 TTL。第二,权威列表不要固定写成静态表,dig NS example.com +short 拿全再逐个用 @ 查;anycast 厂商返回四五个 NS 是常态,漏一个就是你提到的「时好时坏、重试又过」。

再补充一个更隐蔽的坑:失败之后重试不能太频繁。LE 对同一账户同一主机名的 failed validation 有每小时限流,--force 连着打很容易触发 too many failed authorizations,把续期硬卡住一小时,比等几分钟再试亏得多。所以先按你说的,看 acme.sh 原始错误定性——DNS problem: NXDOMAIN 是权威没同步,unauthorized 多半是记录值写错——确认清楚再推进。

acme-dns 创建子域时写占位记录,我印象里也是专门为了避开 NODATA 负缓存,但具体行为还是自己 dig 一次最保险。