example.com 是好的。你把 blog.example.com 指到博客托管,等了 10 分钟,结果还是 DNS_PROBE_FINISHED_NXDOMAIN、This site can't be reached 或 ERR_NAME_NOT_RESOLVED。根域名能解析,子域名解析不了。
最快的修复: 跑 dig blog.example.com @1.1.1.1 +short。如果什么都没返回,说明你根本没建那行 DNS 记录(情况 1)。如果返回了 IP 但页面报错,说明 DNS 是通的,只是你忘了在主机面板里把子域名绑上去(情况 3)。这两类占了绝大多数报障。这种问题几乎从来不是传播等待,也不是浏览器的锅。
本文按这五类实际发生的顺序逐一排查。
先判断属于哪一种
先来一条查询。直接问公共 resolver,免得你笔记本的本地缓存骗你:
dig blog.example.com +short
dig blog.example.com @1.1.1.1 +short
nslookup blog.example.com 8.8.8.8
对照预期:
dig 结果 | 含义 | 看哪一节 |
|---|---|---|
空 / NXDOMAIN | 子域名根本没有 DNS 记录 | 情况 1 |
| 返回一个 CNAME,但链到的最终目标不存在 | 记录指向了死掉的目标 | 情况 2 |
返回了 IP,但页面报错(ERR_SSL_PROTOCOL_ERROR、404、“not found”) | DNS 通了,主机不认这个子域名 | 情况 3 |
| 返回了错误的 IP | 旧记录或通配把它挡住了 | 情况 4 |
@1.1.1.1 正确但本地 ISP resolver 不对 | 传播 / 负缓存延迟 | 情况 5 |
情况 1:子域名根本没有 DNS 记录
你加了 example.com(apex),但从没给 blog 这行加过记录。DNS 不会自动生成子域名。
怎么看:dig blog.example.com +short 返回空。DNS provider 面板里没有 blog(或 blog.example.com,看显示风格)这一行。
修复:在权威 DNS provider(用 dig NS example.com +short 看是哪家——真正应答的是这家的 nameserver,它可能和你的注册商不是一回事)加一行 A 或 CNAME:
- 静态托管(Vercel / Netlify / Cloudflare Pages / GitHub Pages):用 CNAME,例如
CNAME blog -> your-site.netlify.app.——按主机自定义域面板里给的确切目标值填。 - 指向服务器 IP:
A blog -> 203.0.113.42。 - apex(
@)不能是 CNAME,但子域名可以——主机给的是主机名而不是 IP 时就用 CNAME。参见 A vs CNAME 混淆。
情况 2:记录存在但目标已经死了
dig 返回了 CNAME,但这个 CNAME 链到的最终目标 NXDOMAIN,或者那个 IP 早就不再托管任何东西了。
怎么看:
dig blog.example.com +trace
# 跟着 chain 看。最后是 "no servers could be reached"
# 或 NXDOMAIN,就是最终目标死了。
修复:把 CNAME / A 改到当前正确的目标。如果换了主机,旧的 cname.heroku-app.com 之类已经废了,要换成新主机给的值。换主机之后,还要顺手删掉旧平台留下的 AAAA(IPv6)记录——有些主机(比如 Render)只走 IPv4,一行残留的 AAAA 会把你一部分流量送进黑洞。
情况 3:DNS 通了但主机不认这个子域名
Vercel / Netlify / Cloudflare Pages 最经典的坑,也是仅次于情况 1 的高发原因。DNS 指向是对的,但主机的项目里没把 blog.example.com 加到域名列表,于是主机边缘返回一个通用 404、一张 “Site not found” 页,或者用错证书的 SSL 握手错误。
怎么看:
curl -vI https://blog.example.com 2>&1 | head -30
# 典型征兆:
# - SSL 证书是 *.vercel.app 而不是你的域名
# - HTTP/2 404,正文是 "The deployment could not be found on Vercel"
# - Netlify 的 "Site not found" / "Not Found" 页
# - Cloudflare Error 1000("DNS points to prohibited IP")或 522,
# 在 Pages 上 522 通常意味着你在 Pages 面板里认领域名之前
# 就先加了 CNAME
修复:在主机面板里显式加上 blog.example.com,然后让它去签证书:
- Vercel:Project -> Settings -> Domains -> Add。注意,截至 2026 年 6 月,Vercel 给每个项目分配的是独立的 CNAME 目标,形如
d1d4fc829fe7bc7c.vercel-dns-017.com.(老的cname.vercel-dns.com.仍然可用,但面板里显示的是这个按项目生成的值)。跑vercel domains inspect example.com可以打印出你项目要用的确切记录。 - Cloudflare Pages:Pages 项目 -> Custom domains -> Set up。必须先在这里加域名;在面板里认领之前就把 CNAME 指向
your-project.pages.dev.,会返回 522。 - Netlify / Render / Fly:在项目里加自定义域,然后点 Verify。
这是个双边握手:DNS provider 那行记录 + 主机端绑定域名,缺一不可。要先在主机端加域名,证书才签得出来——主机要靠你刚配的 DNS 来验证归属,所以 DNS 得先生效。
情况 4:通配或旧记录把子域名挡住了
*.example.com CNAME -> some-old-host 这种通配,在没有更精确记录时会命中 blog.example.com。或者你有两行互相冲突的 blog 记录(A + CNAME,DNS 规范禁止;或两行 A 指向不同 IP)。
怎么看:
dig blog.example.com +short
# 返回一个意料之外的 IP,仔细一看是你另一个项目的 IP
然后在 DNS 面板里找:有没有 * 行、有没有以前同事加的 blog 行、有没有被某个早忘掉的平台集成偷偷加上的 blog 行。
修复:精确的 blog 记录永远优先于 *,所以加上正确的那行就好了。删掉重复项,确保 blog 每种类型只留一行。参见 通配 DNS 不匹配子域名。
情况 5:真的就是传播延迟
比大家想象的少见得多。如果 blog 这行是刚加的,而你之前在它还不存在时查过,你的 resolver 就按它自己的负缓存 TTL(通常是 zone 的 SOA minimum,常见 5-60 分钟)把 NXDOMAIN 缓存了下来,于是它在过期之前会一直返回 NXDOMAIN。
怎么看:dig @1.1.1.1 和 @8.8.8.8 都通,但本地 ISP 的 resolver 不通;或反过来。whatsmydns.net 上有的地区打勾、有的打叉。
修复:等负缓存 TTL 过去,同时把本地缓存清掉:
# macOS
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
# Linux (systemd-resolved)
sudo resolvectl flush-caches
# Windows
ipconfig /flushdns
然后开一个全新的无痕窗口硬刷。参见 DNS 传播困惑。
最短修复路径
按命中率排序:
dig NS example.com +short—— 找到权威 DNS provider。子域名加在那里,不是注册商(如果两者不同的话)。- 同时在主机面板里加这个子域名 —— Vercel / Netlify / Cloudflare Pages / Render / Fly 都需要这一步。这是最容易被跳过的一步。
- 等几分钟,再
dig blog.example.com @1.1.1.1 +short,确认能看到主机给的主机名或 IP。 - 看主机面板的 SSL 状态 —— DNS 验证通过后通常 1-5 分钟内由 Let’s Encrypt 签好。
- 还不行,找有没有通配或重复行把子域名挡住了。
各主机的子域名配置参考
下表的值对照各厂商官方文档,截至 2026 年 6 月核对。务必复制你自己面板里显示的确切目标——好几家主机现在都按项目生成独立的值。
| 主机 | DNS provider 处的记录 | 主机面板的动作 |
|---|---|---|
| Vercel | CNAME blog -> <unique>.vercel-dns-017.com.(或老值 cname.vercel-dns.com.) | Project -> Settings -> Domains -> 添加 blog.example.com |
| Netlify | CNAME blog -> your-site.netlify.app. | Site -> Domain management -> Add a domain |
| Cloudflare Pages | CNAME blog -> your-project.pages.dev. | Pages -> Custom domains -> Set up(先加域名) |
| Firebase Hosting | A 指向 “Add Custom Domain” 向导给的两个 IP | Hosting -> Add custom domain |
| GitHub Pages | CNAME blog -> username.github.io. | 仓库 Settings -> Pages -> Custom domain |
| Render | CNAME blog -> your-service.onrender.com.(删掉所有 AAAA) | Service -> Settings -> Custom Domains -> Verify |
CNAME 值大小写不敏感,但不能带 https:// 前缀或结尾 /。结尾那个点表示完全限定域名,多数 DNS 界面会自动补上。GitHub Pages 还要注意:仓库里的 CNAME 文件(全大写、只能写一个域名)必须能扛过你的构建——很多静态站点生成器会把它覆盖掉,于是下一次部署时自定义域就默默坏了。
怎么确认已经修好
dig blog.example.com @1.1.1.1 +short返回主机的主机名或 IP(不是空、不是错误的 IP)。curl -sI https://blog.example.com | head -1返回HTTP/2 200(或你想要的跳转),而不是 404 / 522 / 1000。- TLS 证书匹配你的域名:
echo | openssl s_client -connect blog.example.com:443 -servername blog.example.com 2>/dev/null | openssl x509 -noout -subject显示CN = blog.example.com(或你这个 zone 的通配证书),而不是*.vercel.app之类。 - 主机面板里这个域名显示绿色的 “Valid configuration” / “Active” 状态,且 SSL 已签发。
预防
- 子域名指向托管平台时优先用 CNAME,而不是 A。 主机偶尔会悄悄换 IP 扩容,CNAME 跟随者会自动跟上。
- 没有真实需要就别加通配 CNAME
*.example.com。 通配让新子域名”开箱即用”,但也会吃掉拼错的子域名、挡掉你正常添加的精确行。 - 新子域名加完立刻在手机网络或
@1.1.1.1上测一次。 你笔记本的 DNS 缓存会骗你。 - 在团队文档里写清楚每个子域名归哪个主机:
blog-> Ghost、app-> Vercel、status-> 某个状态页服务。半年后排查起来快得多。 - 稳态下子域名 CNAME 的 TTL 保持 3600 —— 缓存命中够高,需要切换时一小时内也能切。
FAQ
问:5 分钟前刚加的 CNAME,为什么还没解析?
答:新记录传到公共 resolver 只要几秒。但如果你在加之前就查过这个子域名,你的 resolver 已经按它自己的负缓存 TTL(通常 5-60 分钟)把 NXDOMAIN 缓存了。等它过期,或者换一个 resolver 查:dig blog.example.com @1.0.0.1 +short。
问:访问子域名时跳出 Vercel / Netlify 的 “Site not found” 页,或者 Cloudflare 的 522。
答:DNS 是对的(确实打到了主机边缘),但项目没认领这个主机名。在项目的 domain settings 里加上 blog.example.com。Cloudflare Pages 上的 522 专门意味着:你在 Custom domains 里认领域名之前就先加了 CNAME。
问:子域名需要自己的 SSL 证书吗? 答:要,但现代托管都会在 DNS 验证通过的几分钟内通过 Let’s Encrypt 自动签发。如果 1 小时后 SSL 还卡着,先看 zone 上有没有挡路的 CAA 记录,再看 自定义域 SSL 延迟。
问:能像 CNAME 子域名一样 CNAME 根域名(example.com)吗?
答:不能。RFC 1034 禁止在 zone apex 上配 CNAME,因为会和 SOA / NS 记录冲突。要么用 A 记录,要么用 DNS provider 的 “CNAME flattening” / “ALIAS” / “ANAME” 功能(Cloudflare 和 DNSimple 都支持)。
问:子域名能打开,但会跳转到根域名。
答:要么主机有”强制根域名”重定向设置,要么你的 CMS / 框架在服务端发了 Location: https://example.com。curl -I https://blog.example.com 看一下——301 到 apex 说明是重定向问题,跟 DNS 无关。
问:Vercel / GitHub 说我的 DNS 配错了,可 dig 看着是对的。
答:主机会拿它预期的确切目标来校验。Vercel 现在按项目分配 CNAME 值,所以一个通用的 cname.vercel-dns.com. 可能跟面板想要的对不上——跑 vercel domains inspect example.com 把那个值复制过去。GitHub 的 “DNS check unsuccessful” 多半是 CNAME 指向了错误的 username.github.io,或者仓库里那个大写 CNAME 文件被你的构建覆盖掉了。