你在 Vercel、Cloudflare 或 Firebase 上绑了自定义域名。DNS 能解析,中间也没有代理,但 SSL 证书一直卡在 “pending” 或 “generating”,永远发不出来。如果你能看到平台日志,里面会写类似 CAA record prevents issuing the certificate 或 CAA record for yourdomain.com prevents issuance 的报错。原因几乎总是一条遗留的 CAA DNS 记录——可能是上一次配 CA 时留下的,也可能是 registrar 的默认值——它只允许某个你新主机不用的证书颁发机构(CA)。CA 一去签发,发现自己不在白名单里就停手了。没有重试循环,控制台里也没有醒目的报错,就是证书一直不出现。
最快修法: 跑 dig CAA yourdomain.com +short。只要有返回,要么把所有 CAA 记录删掉(这样任何 CA 都能签),要么给你主机的 CA 加一条 issue 记录。Vercel 需要 0 issue "letsencrypt.org"。Cloudflare 和 Firebase 默认用 Google Trust Services,所以还要加 0 issue "pki.goog; cansignhttpexchanges=yes"(Cloudflare 官方文档用的就是这个完整写法——光写 pki.goog 不一定够)。等 TTL 过了,再重新触发签发。完整排查见下文。
你属于哪一类?
| 症状 | 可能原因 | 跳转 |
|---|---|---|
dig CAA 返回 issue 记录,但没有你主机的 CA | 旧配置留下的限制性 CAA | 原因 1 |
你从没设过 CAA,但 dig 有返回 | registrar / DNS 商默认 | 原因 3 |
| 子域没 CAA,apex 有 | apex 的 CAA 向下继承 | 原因 4 |
只有通配(*.)证书签不出 | 缺 issuewild | 原因 5 |
dig CAA 报 SERVFAIL / DNSSEC 错 | DNSSEC 坏了,CAA 查询失败 | 原因 6 |
dig CAA 什么都不返回但证书仍卡住 | 不是 CAA 问题——见相关阅读 | 相关阅读 |
常见原因
按命中率从高到低。
1. CAA 只允许了另一个 CA
你(或同事)几个月前为了安全设过 CAA,比如 0 issue "digicert.com",意思是只有 DigiCert 能签。后来你换到了用别的 CA 的主机。截至 2026 年 6 月,Cloudflare 和 Firebase 默认会去找 Google Trust Services(pki.goog),所以一条既不放行 Google Trust Services、也不放行 Let’s Encrypt 的 CAA 会把它们彻底挡死。
怎么判断:
dig CAA yourdomain.com +short
限制性记录长这样:
0 issue "letsencrypt.org"
0 issue "digicert.com"
如果你主机的 CA 不在这个列表里,签发就被挡了。
2. 主机用了你没料到的 CA
主机这些年会换 CA,而且不少主机现在同时用好几个。两年前写的 CAA 很可能不允许今天主机选用的那个 CA。
- Vercel 只通过 Let’s Encrypt 签发。Vercel 域名上的任何自定义 CAA 都必须包含
0 issue "letsencrypt.org"。 - Cloudflare 可以用 Google Trust Services、Let’s Encrypt、SSL.com 或 Sectigo。截至 2026 年 6 月,按它官方 SSL/TLS 文档的说法,默认行为是永远先尝试 Google Trust Services,只有当 CAA 记录把 Google 挡住时才回退到 Let’s Encrypt。所以一条只允许 Let’s Encrypt 的 CAA 会把 Cloudflare 逼到用 Let’s Encrypt,而一条两者都不放行的 CAA 则会把所有签发都挡死。
- Firebase Hosting 用 Google Trust Services(
pki.goog)或 Let’s Encrypt(letsencrypt.org)签发,由它自动选择;完全没有 CAA 时两者都可用,只有当 Firebase 检测到已有记录会挡住签发时,它才会提示你加 CAA。两个值都留着,续期时它就能挑当时健康的那个。 - Netlify 通过 Let’s Encrypt 签发。
怎么判断: 把 dig CAA 返回的 issue 值跟上面这份 CA 清单对一对。没有交集,那就是它在挡。
3. CAA 从 registrar 或 DNS 默认继承
有些 registrar 和 DNS 商会替你加 CAA。如果你用 Cloudflare 作为 DNS 服务商,当它发现你现有的 CAA 会把它所有 CA 都挡掉时,甚至会替你补上 CAA 记录——于是你会看到自己从没敲过的记录。
怎么判断: 哪怕你确信自己从没设过 CAA,也跑一下 dig CAA yourdomain.com +short。只要非空,就是有谁设了默认值。
4. apex 的 CAA 会被子域继承
CAA 是由 CA 沿域名树往上爬的:如果 app.example.com 自己没有 CAA,CA 就去查 example.com,再往上查它的父级,依此类推。所以即使 app.example.com 的记录全对,apex 的 CAA 仍然管着这个子域。
怎么判断:
dig CAA app.example.com +short
dig CAA example.com +short
子域什么都不返回、但 apex 返回了限制性的 issue 记录,那挡你的就是 apex 的 CAA。
5. 通配证书需要 issuewild
issue 同时授权普通证书和通配证书——除非同时还存在 issuewild 记录。按 RFC 8659,只要有任何 issuewild,它对通配(*.example.com)签发就优先生效,此时 issue 记录不再适用于通配证书。所以单主机证书签得好好的域名,通配证书仍可能签不出来。
怎么判断: 如果只有通配证书失败,检查有没有 issuewild 条目。要么删掉,要么给你主机的 CA 加一条 issuewild,比如 0 issuewild "letsencrypt.org"。
另外提一句:0 iodef "mailto:..." 只是一个事件上报联系人,从不限制签发。只有 issue 和 issuewild 决定证书能不能签出来。
6. CAA 查询报 SERVFAIL(DNSSEC 坏了)
这条是新出现的、很容易漏掉。按 CA/Browser Forum 的 Ballot SC-085v2,自 2026 年 3 月 15 日起生效,CA 在做 CAA 和域名控制验证查询时,必须对已启用 DNSSEC 的域名做 DNSSEC 校验。如果你的区域开了 DNSSEC 但坏了(RRSIG 过期、TLD 上的 DS 记录跟你的 DNSKEY 对不上、或用了不支持的算法),CA 的校验解析器会把应答判为 BOGUS、在查 CAA 时返回 SERVFAIL,于是签发被拒——哪怕你的 CAA 内容完全没问题。完全没开 DNSSEC 的域名不受这条规则影响。
怎么判断:
dig CAA yourdomain.com +dnssec
出现 SERVFAIL 状态,或者明明发布了 DS 记录、返回里却缺 ad(authenticated-data)标志,都指向 DNSSEC 而非 CAA 内容。先修好 DNSSEC 信任链(见 开启 DNSSEC 后 SERVFAIL),再动 CAA 的值。
最短修复路径
第 1 步:列出所有现有 CAA 记录
dig CAA yourdomain.com +short
dig CAA www.yourdomain.com +short # 子域可能有自己的
把每个 issue 和 issuewild 值都记下来。如果两条都返回空,那 CAA 不是你的问题——直接跳到相关阅读。
第 2 步:弄清你主机用哪个 CA
根据上面的调查,截至 2026 年 6 月:
| 主机 | 证书颁发机构 | 要放行的 CAA issue 值 |
|---|---|---|
| Vercel | Let’s Encrypt | letsencrypt.org |
| Cloudflare | Google Trust Services(默认),回退 LE;也用 SSL.com / Sectigo | pki.goog; cansignhttpexchanges=yes,保险起见再加 letsencrypt.org ssl.com sectigo.com |
| Firebase Hosting | Google Trust Services + Let’s Encrypt(自动选) | pki.goog 和 letsencrypt.org |
| Netlify | Let’s Encrypt | letsencrypt.org |
Cloudflare 这边要特别注意:它文档里公布了自己期望的记录,对 Google Trust Services 来说就包含 cansignhttpexchanges=yes 这个参数以及一条对应的 issuewild。如果你的主机不在表里,开个支持工单直接问:“自定义域名的 SSL 你们用哪个 CA?“
第 3 步:要么加主机的 CA,要么删掉 CAA
选项 A——加上你主机的 CA:
yourdomain.com CAA 0 issue "letsencrypt.org"
yourdomain.com CAA 0 issue "pki.goog; cansignhttpexchanges=yes"
yourdomain.com CAA 0 issue "sectigo.com"
yourdomain.com CAA 0 issue "ssl.com"
保留你已有的条目,再补上主机需要的。列多个 CA 没问题,如果你主机会从一个 CA 池里挑(比如 Cloudflare),这反而更稳妥。注意 Google Trust Services 那条带了 cansignhttpexchanges=yes 参数——这是 Cloudflare 文档里用的完整字符串,漏掉它是 pki.goog 的 CAA 仍被拒的常见原因。如果你还要签通配证书且存在任何 issuewild 记录,给同一个 CA 再加一条 issuewild,比如 0 issuewild "pki.goog; cansignhttpexchanges=yes"。
选项 B——直接删掉 CAA:
删掉所有 CAA 记录。没有 CAA 时,任何公开受信任的 CA 都能签。这更简单,对多数站点也够用;代价是失去 CAA 那点(不大的)防误签保护。
Vercel 这边要特别注意:如果你的域名是通过 Vercel 的 CNAME 指过去的,你会继承 Vercel 的 CAA,没法在那个子域上设自己的。要自己控制 CAA,就把 CNAME 换成 Vercel 的 A 记录,再加上 0 issue "letsencrypt.org"。
第 4 步:等 TTL 过,再验证传播
CAA 变更按记录的 TTL 传播;留几小时余量,顽固情况下可能要到 24 小时。用多个公共解析器验证:
dig CAA yourdomain.com @8.8.8.8 +short
dig CAA yourdomain.com @1.1.1.1 +short
两边都应返回你的新值。如果某一边还显示旧值,说明还没传播完——先别急着重新触发签发。
第 5 步:重新触发证书签发
大多数控制台都有 “Retry”、“Refresh” 或 “Remove and re-add domain” 操作。触发一次就好,别反复点——CA 有速率限制(Let’s Encrypt 对每个账户/主机名每小时允许的失败验证次数有限),反复删了重加可能把你这一小时锁死。等待期间最多每小时一次。
第 6 步:确认修好了
curl -sI https://yourdomain.com | head -3
你要的是 HTTP/2 200,且没有 TLS 报错。然后确认签发方就是你放行的那个 CA:
echo | openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null | openssl x509 -noout -issuer -dates
issuer= 那一行应该写着你授权的 CA(比如 Let's Encrypt 或 Google Trust Services),notBefore 应该是最近的日期。也可以在浏览器里点锁图标,看证书的签发方和有效期。
预防建议
- 换主机之前先查清它用哪个 CA,并在同一次变更里更新 CAA。
- 没有真正的安全理由就别设限制性 CAA;对多数站点来说完全不设 CAA 就行。
- 子域要记住 apex 的 CAA 会向下继承——在 apex 上修,或者按子域逐个覆盖。
- 任何 CAA 变更后,等 TTL 过、用两个公共解析器验证之后再重新触发签发。
- 保持 DNSSEC 健康;自 CA/Browser Forum 的 Ballot SC-085v2 在 2026 年 3 月 15 日生效后,DNSSEC 信任链坏掉会让 CAA 查询 SERVFAIL,哪怕你的 CAA 值正确也会被挡。
- 在 DNS 笔记里记下每条 CAA 为什么存在,免得将来的你又被它绊倒。
常见问题
我到底需不需要 CAA 记录? 不需要。CAA 是可选的。没有 CAA 记录时,任何公开受信任的 CA 都能为你的域名签发。只有当你想出于安全或合规把签发限制到特定 CA 时,CAA 才有意义。
我把 CAA 记录删了,证书还是签不出来,为什么?
要么是变更还没传播(按你的旧 TTL,用 dig ... @8.8.8.8 +short 再查一遍),要么这本来就不是 CAA 的锅。如果 dig CAA 现在到处都返回空、签发仍失败,那就去看 DNSSEC SERVFAIL、实际的 A/AAAA/CNAME 目标,或者域名控制验证——见 SSL 证书还在 pending。
Vercel 需要哪个 CAA 值?
0 issue "letsencrypt.org"。Vercel 只通过 Let’s Encrypt 签发,所以 Vercel 域名上的任何自定义 CAA 都必须包含这一行。
Cloudflare 一直提示我从 Let’s Encrypt 切到 Google Trust Services,我该加什么 CAA?
加 0 issue "pki.goog; cansignhttpexchanges=yes"(如果你要签通配证书,再加 0 issuewild "pki.goog; cansignhttpexchanges=yes")。这是 Cloudflare CAA 文档里给出的完整写法;光写 pki.goog 是 CAA 仍然失败的常见原因。截至 2026 年 6 月,Cloudflare 默认先试 Google Trust Services、只有 CAA 把 Google 挡住时才回退到 Let’s Encrypt,所以把 letsencrypt.org、ssl.com、sectigo.com 也一并留着,可以让它在 CA 池里挑。
单主机证书没问题,但通配证书签不出,差在哪?
你几乎肯定有一条把你主机 CA 排除在外的 issuewild 记录。按 RFC 8659,通配证书时 issuewild 覆盖 issue。加一条对应的 0 issuewild "yourca.tld",或者把 issuewild 记录删掉。
我的 CAA 值看着没问题,但 CA 还是报 CAA 查询 SERVFAIL,怎么办?
自 2026 年 3 月 15 日起,如果你的区域开了 DNSSEC 但坏了,CA 的解析器会在查 CAA 时返回 SERVFAIL 并拒绝签发。跑一下 dig CAA yourdomain.com +dnssec:出现 SERVFAIL 状态,或者明明发布了 DS 记录、返回里却缺 ad 标志,都指向 DNSSEC 而非 CAA 内容。先修好信任链(如果你其实不需要 DNSSEC,就在 registrar 删掉 DS 记录、关掉 DNSSEC)再重试。见 开启 DNSSEC 后 SERVFAIL。
改完 CAA 该等多久? 至少等记录的 TTL,通常是几分钟到一小时。给到 24 小时再下”失败”的结论,并用两个独立解析器确认后再重新触发。
相关阅读
- SSL 证书还在 pending
- DNS 改了但站点还是打不开
- 通配 DNS 不命中三级子域
- 同一域名在 Vercel 工作但 Firebase 不行
- 域名连接后站点时而能开时而不能:4 个原因 + 对症修复
- 浏览器 SSL Mixed Content 警告
- 证书被拒:Certificate Transparency 日志不匹配 —— 排查指南
- Cloudflare 橙云灰云搞反,站点立刻挂 —— 排查与修复
- 开启 DNSSEC 后 SERVFAIL:信任链断了 —— 排查与修复
- HSTS preload 进了就出不来:站点被锁死在 HTTPS
- IPv6 用户打不开站点:AAAA 记录缺失或挂了 —— 完整排查
- 子域 NS 委派挂了:缺 Glue 记录 —— 排查与修复
标签: #排查