你在 Vercel / Firebase / Netlify 绑了自定义域名。控制台显示 “SSL certificate pending”,或者 HTTP 能正常打开、但 HTTPS 报 NET::ERR_CERT_AUTHORITY_INVALID。30 分钟过去了,1 小时过去了。
最快的修法: 这三个平台都用 Let’s Encrypt,它要满足两个条件才发证——(1) 你的域名能解析到平台(而不是旧主机);(2) 平台能完成一次 ACME challenge,通常是 HTTP-01,也就是去拉 http://yourdomain.com/.well-known/acme-challenge/<token>。所以先查两件事:用 dig 确认 DNS 指向平台、不是旧主机;如果域名走了 Cloudflare 代理(橙云),把它改成 “DNS only”(灰云)。大部分卡住的证书都出在这两条。下面是排查其余情况的有序清单。
一个让人安心的事实:1 小时内显示 “pending” 是正常的。Netlify 在头 24 小时里每 10 分钟重试一次;Firebase 最长可能要 24 小时。DNS 没真正搞对之前,别急着大动干戈。
你属于哪一种?
| 症状 | 最可能的原因 | 跳到 |
|---|---|---|
dig 返回的是旧主机 IP | DNS 没传播 / 记录类型错 | 原因 1、4 |
| 域名走 Cloudflare,证书一直发不出 | 橙云代理截了 challenge | 原因 3 |
| 控制台报错里提到 CAA | CAA 记录挡了 Let’s Encrypt | 原因 2 |
| Firebase 状态卡在 “Needs setup” / pending | 有冲突的 A / CNAME / AAAA 记录 | 原因 4、6 |
| 控制台说 “Domain not verified” | 没加所有权 TXT | 原因 5 |
| 证书已发但浏览器还报错 | 浏览器里残留的 HSTS | 原因 7 |
常见原因
按命中率从高到低排列。
1. DNS 还没传播
发证器要去拉 http://yourdomain.com/.well-known/acme-challenge/<token>。DNS 还没到发证器用的 resolver,challenge 就失败,平台稍后再重试。
怎么判断:
dig yourdomain.com +short
还没返回平台的 IP/CNAME,就是没传播。用本机 resolver 之外的角度再交叉验证一下:dnschecker.org 或 Google 的 Admin Toolbox Dig——各地区传播进度不一致,发证器查到的那台 resolver 可能还没更新。
2. CAA 记录挡了 Let’s Encrypt
如果你的 zone 里有 0 issue "digicert.com" 这种 CAA 记录,就只有 DigiCert 能发证,Let’s Encrypt 的请求会被拒,平台会显示 CAA 错误。
怎么判断:
dig CAA yourdomain.com +short
看到 CAA 记录、且没有一条允许 letsencrypt.org,就是这条。注意:完全没有 CAA 记录时任何 CA 都能发证,这才是安全的默认值。(apex 和父级 zone 都要看,因为 CAA 是继承的。)
3. Cloudflare 代理(橙云)截了 challenge
Cloudflare 代理你的 DNS(橙云)时,它自己来终止 TLS、挡在源站前面。平台没法把 HTTP-01 的 challenge 响应送出去,Cloudflare 还可能返回缓存的或被重定向的响应,验证就失败。Netlify 把话说得很直白:它”必须自己终止 TLS 才能签发证书”,所以任何挡在前面的服务都得先关掉。
怎么判断: Cloudflare 的 DNS 列表里,apex(和 www)的 A/CNAME 显示橙云(Proxied)。初次发证时必须是灰云(DNS only)。
4. 记录类型错或有残留的冲突记录
每个平台都要求特定的记录类型和值。该用 A 却设成 CNAME(或旧主机留下的残记录),都会挡住发证。
- Vercel apex:用
A记录。76.76.21.21现在仍可用,但 Vercel 现在会按项目生成各自的值——以 Project → Settings → Domains 上显示的为准,或跑vercel domains inspect yourdomain.com。www:CNAME指向cname.vercel-dns.com(较新的项目可能显示*.vercel-dns-NNN.com这种目标,以控制台显示的为准)。 - Netlify apex:
A指向75.2.60.5。www:CNAME指向<你的站点>.netlify.app。 - Firebase: 用 Connect Domain 弹窗里给出的那几条
A记录,并删掉所有指向别处的 A、CNAME、AAAA——只要还有这类记录存在,Firebase 就无法签发证书。
怎么判断: 把 dig 输出和控制台显示的值逐条对比,记录类型别即兴发挥。
5. 平台还没验证域名所有权
有些场景要求先加一条所有权 TXT 记录才发 SSL。加了域名却跳过验证,控制台就会一直 “pending”。
怎么判断: 在平台控制台找 “Verify ownership”、“Domain not verified” 或 Verify 提示,把它给的 TXT 加上。
6. AAAA 记录指向别处
A 记录指对了,但 AAAA(IPv6)还指向旧主机。发证器可能偏好 IPv6,结果打到错的目标。
怎么判断:
dig AAAA yourdomain.com +short
AAAA 指向别处就删掉或更新。(Firebase 尤其如此:只要有残留的 AAAA,发证就会失败。)
7. 浏览器里残留的 HSTS
证书其实已经发出来了,但浏览器记着旧的 HSTS 条目,只肯走那个坏掉的 HTTPS、不肯回退。这不影响发证——它只是掩盖了”已经成功”的事实。
怎么判断: 控制台都报证书已签发了,浏览器还在 NET::ERR_CERT_AUTHORITY_INVALID。Chrome 里到 chrome://net-internals/#hsts → “Delete domain security policies” 清掉它,再开个无痕窗口试。
最短修复路径
第 1 步:用 dig 验证 DNS
dig yourdomain.com +short # apex 的 A 记录
dig www.yourdomain.com +short # 解析 www 的 CNAME 链
两条都应返回平台期望的值。还显示旧主机 IP,就是 DNS 没完全到位——先在 dnschecker.org 上确认全球都传播好了,再做别的。
第 2 步:查 CAA
dig CAA yourdomain.com +short
看到 0 issue "digicert.com" 这种限制性记录,要么加 0 issue "letsencrypt.org",要么把 CAA 记录整条删掉(没有 CAA = 任何 CA 都能发)。如果想安全地把发证锁到某一个平台,就别只锁 CA、而是锁它的 ACME 账号——比如 Netlify 就文档化了一个绑定其 Let’s Encrypt 账号的 accounturi CAA 值。
第 3 步:临时把 Cloudflare 改成 “DNS only”
到 Cloudflare → DNS → Records → 对 apex 和 www,点橙云让它变灰(DNS only)。等 1-2 分钟,再到平台控制台重新触发发证。
证书发出后可以重新开代理(橙云)。续签能穿过 Cloudflare,因为平台会改用 DNS-01 或复用已缓存的授权。如果必须在发证期间保持橙云开着,另一个办法是建一条 Cloudflare Configuration Rule,把 /.well-known/acme-challenge/* 这个路径强制走纯 HTTP 且关掉缓存——但临时改灰云两分钟更简单。
第 4 步:确认记录类型和值跟控制台一致
从平台拉出确切的值,再用 dig 比对:
- Vercel:
vercel domains inspect yourdomain.com(或 Project → Settings → Domains)。 - Netlify:Domain management 里为你站点显示的记录(apex
A 75.2.60.5,www CNAME <site>.netlify.app)。 - Firebase:Connect Domain 弹窗里的
A记录;其余的 A/CNAME/AAAA 全删。
apex 绝不要用 CNAME——DNS 规范禁止在 zone 根上用 CNAME(RFC 1034)。按你 DNS 服务商的支持,用 A 或 ALIAS/ANAME。
第 5 步:重新触发发证
修完 DNS / CAA / 代理后:
- Vercel: Project → Settings → Domains → 点 Refresh,或者删了重加域名。
- Netlify: Domain management → HTTPS → Verify DNS configuration,再点 Provision certificate。
- Firebase: Hosting → 在 Connect Domain 弹窗里点 Verify;之后状态会自己往前走(没有手动发证按钮)。
第 6 步:等,但别来回折腾
多数平台按固定节奏重试:Netlify 头 24 小时每 10 分钟一次;Vercel 几分钟内复查;Firebase 最长 24 小时。不要反复删了重加域名——那会重置你在发证队列里的位置,反而更慢。
第 7 步:怎么确认已经修好
证书生效后,从干净的环境验证,别只看控制台:
curl -svo /dev/null https://yourdomain.com 2>&1 | grep -Ei 'subject:|issuer:|expire'
应该能看到合法的 issuer(比如 Let’s Encrypt / R 系列)和一个未来的过期时间。或者用无痕窗口打开站点——挂锁、没有警告就说明好了。如果浏览器还报错但 curl 正常,那就是命中了缓存的 HSTS(原因 7)。
第 8 步:仍卡住就找平台支持
DNS 正确、CAA 清干净、代理关掉后过了 4 小时以上还 pending,就提工单。附上:
- 域名
dig yourdomain.com +short和dig CAA yourdomain.com +short的输出- 添加域名的时间戳
- 控制台确切报错/状态的截图
预防建议
- 没特别理由别设 CAA;要设就把平台可能用的所有 CA 都列上(Let’s Encrypt、Sectigo 等),或者锁平台的 ACME
accounturi。 - 初次发证前别开 Cloudflare 代理。
- 看控制台之前先
dig——DNS 不对,证书发不出来。 - 严格用平台显示的记录类型和值;apex 绝不用
CNAME替A。 - 把上家主机留下的
A/CNAME/AAAA残记录都删掉,再把 DNS 指到新家。 - 给新域名维护一份
domain-setup.mdrunbook,写清你平台的精确步骤和值。
常见问题
SSL 发证一般要多久? DNS 一旦正确,通常几分钟到 1 小时。Netlify 头 24 小时每 10 分钟自动重试;Firebase 说最长 24 小时。如果 DNS 没问题、又不到 1 小时,就再等等。
都好几个小时了还 pending,最常见的原因是哪个?
DNS 没完全传播到发证器用的 resolver,或者域名还在 Cloudflare 橙云后面。用 dnschecker.org 重查 dig,并确认云已经是灰的。
Cloudflare 代理要一直关着吗?
不用。只在初次发证时改成灰云(DNS only),发完再开回来。续签走 DNS-01 或复用缓存授权,开着代理也没问题。
加一条 CAA 记录能加速吗?
只有当原来有一条限制性 CAA 在挡发证时才有用。如果你压根没有 CAA,就别动——任何 CA 都能发。只有在需要显式放行 Let’s Encrypt 时才加 0 issue "letsencrypt.org"。
证书显示已签发,但浏览器还报 NET::ERR_CERT_AUTHORITY_INVALID。
那是你本机残留的 HSTS/缓存,不是发证问题。清掉 HSTS(chrome://net-internals/#hsts),再用无痕窗口试。
apex/根域名能用 CNAME 吗?
不能——DNS 禁止在 zone 根上用 CNAME(RFC 1034)。用 A 记录,或者用 DNS 服务商的 ALIAS/ANAME 扁平化来在根上实现类似 CNAME 的效果。