子域名不解析:blog.example.com 打不开

根域名正常,但 blog.example.com 报 NXDOMAIN 或 SSL 错。原因几乎都是少了一行 DNS 记录,或者忘了在主机端绑定域名。按五类逐一排查。

example.com 是好的。你把 blog.example.com 指到博客托管,等了 10 分钟,结果还是 DNS_PROBE_FINISHED_NXDOMAINThis site can't be reachedERR_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 传播困惑

最短修复路径

按命中率排序:

  1. dig NS example.com +short —— 找到权威 DNS provider。子域名加在那里,不是注册商(如果两者不同的话)。
  2. 同时在主机面板里加这个子域名 —— Vercel / Netlify / Cloudflare Pages / Render / Fly 都需要这一步。这是最容易被跳过的一步。
  3. 等几分钟,再 dig blog.example.com @1.1.1.1 +short,确认能看到主机给的主机名或 IP。
  4. 看主机面板的 SSL 状态 —— DNS 验证通过后通常 1-5 分钟内由 Let’s Encrypt 签好。
  5. 还不行,找有没有通配或重复行把子域名挡住了。

各主机的子域名配置参考

下表的值对照各厂商官方文档,截至 2026 年 6 月核对。务必复制你自己面板里显示的确切目标——好几家主机现在都按项目生成独立的值。

主机DNS provider 处的记录主机面板的动作
VercelCNAME blog -> <unique>.vercel-dns-017.com.(或老值 cname.vercel-dns.com.Project -> Settings -> Domains -> 添加 blog.example.com
NetlifyCNAME blog -> your-site.netlify.app.Site -> Domain management -> Add a domain
Cloudflare PagesCNAME blog -> your-project.pages.dev.Pages -> Custom domains -> Set up(加域名)
Firebase HostingA 指向 “Add Custom Domain” 向导给的两个 IPHosting -> Add custom domain
GitHub PagesCNAME blog -> username.github.io.仓库 Settings -> Pages -> Custom domain
RenderCNAME blog -> your-service.onrender.com.(删掉所有 AAAA)Service -> Settings -> Custom Domains -> Verify

CNAME 值大小写不敏感,但不能带 https:// 前缀或结尾 /。结尾那个点表示完全限定域名,多数 DNS 界面会自动补上。GitHub Pages 还要注意:仓库里的 CNAME 文件(全大写、只能写一个域名)必须能扛过你的构建——很多静态站点生成器会把它覆盖掉,于是下一次部署时自定义域就默默坏了。

怎么确认已经修好

  1. dig blog.example.com @1.1.1.1 +short 返回主机的主机名或 IP(不是空、不是错误的 IP)。
  2. curl -sI https://blog.example.com | head -1 返回 HTTP/2 200(或你想要的跳转),而不是 404 / 522 / 1000。
  3. 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 之类。
  4. 主机面板里这个域名显示绿色的 “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.comcurl -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 文件被你的构建覆盖掉了。

相关阅读

标签: #排查 #DNS #排查 #子域名