服务器DNS解析失败怎么办?常见原因与解决方法

DNS 是那种"平时完全想不起来、一出问题就全线瘫痪"的基础设施。它的故障表现也很有迷惑性:ping: unknown host 看着像网络断了,但 IP 直连一切正常;网站打不开,但服务器资源、端口、防火墙全都没问题;更麻烦的是"部分地区能访问、部分地区不行",因为不同运营商的递归 DNS 缓存了不同的结果。

这篇文章先讲清楚一次 DNS 解析到底发生了什么,然后列出常见失败原因和对应的诊断命令,重点是 dig +trace 的正确用法、systemd-resolved 带来的 /etc/resolv.conf 变形问题、以及用 hosts 文件做临时验证的技巧。最后给出预防和监控建议。

一、一次 DNS 查询到底走了哪几步

理解流程,才能判断问题出在哪一步。

应用(浏览器/curl)
  → 应用自身缓存(部分应用有,如 Java JVM)
  → 操作系统缓存 + /etc/hosts
  → stub resolver(本机解析器,如 systemd-resolved 的 127.0.0.53)
  → 递归 DNS 服务器(运营商 DNS 或你配置的公共 DNS)
      → 根服务器(.)
      → 顶级域服务器(.com)
      → 权威 DNS 服务器(你的域名解析商)
  ← 逐级返回,按 TTL 缓存

关键点:

递归服务器替你跑腿。 你的服务器只向递归 DNS 发一个查询,剩下从根到权威的迭代查询由递归服务器完成。

各级都有缓存。 操作系统有缓存、递归服务器按 TTL 缓存、应用自己也可能有缓存。所以改了解析记录不会立刻全网生效。

TTL 决定了生效速度。 记录里设置的 TTL(秒)就是各级缓存的最长保留时间。TTL 600 意味着最坏情况下要等 10 分钟才全网生效。

hosts 文件优先级最高。 在 /etc/nsswitch.conf 里 hosts: 行的顺序决定了优先级,通常是 files dns,即先查 hosts 再查 DNS。

常见的记录类型:

类型 用途
A 域名到 IPv4 地址
AAAA 域名到 IPv6 地址
CNAME 别名,指向另一个域名
MX 邮件服务器
NS 权威域名服务器
TXT 文本记录(SPF、域名验证等)
SOA 起始授权记录,包含序列号、刷新间隔等
PTR 反向解析(IP 到域名)

二、先看错误类型:不同返回码含义完全不同

用 dig 查询时,输出头部的 status 字段直接说明了失败类型:

dig www.example.com A
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12345
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
status 含义 常见原因
NOERROR 查询成功 但要看 ANSWER 段是否有记录,为 0 说明记录类型不匹配
NXDOMAIN 域名不存在 记录真的没配、主机名拼错、或者权威服务器没有这条记录
SERVFAIL 服务器失败 最复杂:DNSSEC 校验失败、权威服务器全部不可达、递归服务器故障
REFUSED 查询被拒绝 目标 DNS 服务器不允许你递归(比如拿公共 DNS 当转发器配置错)
无响应/超时 网络问题 UDP 53 被拦、被限速、防火墙问题

看 flags 也有用:ra(Recursion Available)表示服务器支持递归查询;aa(Authoritative Answer)表示这是权威应答。查权威服务器时应该有 aa。

dig @ns1.example.com www.example.com A    # 直接问权威,看是否有 aa 标志

三、用 dig 逐层定位

基本查询

dig www.example.com A                     # 完整输出
dig www.example.com A +short              # 只要结果
dig www.example.com AAAA +short           # IPv6
dig www.example.com ANY +short            # 所有记录(部分服务器不支持)
dig -x 1.2.3.4                            # 反向解析

输出里的 Query time 反映本次查询耗时,正常应在几十毫秒内。持续超过几百毫秒说明递归 DNS 有问题。

dig +trace:完整追踪解析链

这是排查 DNS 问题最重要的一个命令。它会模拟递归服务器的行为,从根服务器开始一路问下去,把每一级的应答都打印出来:

dig +trace www.example.com

输出大致是这样几段:

.                   从根服务器拿到 .com 的 NS 列表
com.                从 .com 服务器拿到 example.com 的 NS 列表
example.com.        从 example.com 的权威服务器拿到 www 的 A 记录

怎么用它判断问题在哪:

卡在哪一段 说明
根服务器段就没响应 本机网络有问题,或 UDP 53 出网被封
能到 .com 但到 example.com 无响应 权威 DNS 服务器全部不可达或配置错误
到了权威服务器但返回 NXDOMAIN 记录真的不存在,去解析控制台检查
全程正常但 dig 不加 +trace 时结果不对 递归 DNS 的缓存或劫持问题

最后一种情况特别有诊断价值:dig +trace 拿到的是权威的真实答案,直接 dig 拿到的是递归服务器给你的答案。两者不一致时,问题就在递归 DNS 上(缓存、污染、或劫持)。

用多个公共 DNS 对比

这是判断"是不是本地 DNS 有问题"最快的办法:

for dns in 223.5.5.5 119.29.29.29 114.114.114.114 8.8.8.8; do
  echo "== $dns =="
  dig @$dns www.example.com A +short
  dig @$dns www.example.com A | grep -E 'Query time|status:'
done
公共 DNS 地址
阿里 223.5.5.5、223.6.6.6
DNSPod 119.29.29.29
114DNS 114.114.114.114
Google 8.8.8.8、8.8.4.4
Cloudflare 1.1.1.1

对比结果的几种情况:

  • 所有 DNS 结果一致且正确 → DNS 没问题,查别的
  • 所有 DNS 都返回 NXDOMAIN → 记录真的没配,去控制台加
  • 只有本地 DNS 结果不同 → 本地 DNS 缓存污染或劫持
  • 境外 DNS 正常、境内 DNS 异常 → 可能是域名状态问题(如未实名被暂停)

用 TCP 模式排除 UDP 限速

DNS 默认用 UDP 53,但响应超过 512 字节(启用 DNSSEC 后更容易超过)时会转用 TCP。如果 UDP 53 被限速或丢包,就会出现"时好时坏"的解析失败:

dig +tcp @8.8.8.8 www.example.com A

如果 TCP 模式稳定而 UDP 模式超时,基本可以确定是 UDP 53 被限速或丢包。

其他有用的 dig 用法

dig example.com NS +short             # 看权威服务器有几个、是否可达
dig example.com SOA +short            # 看序列号,判断是否已更新
dig example.com MX +short             # 邮件记录
dig +dnssec www.example.com           # 看 DNSSEC 相关记录
dig www.example.com +stats            # 只看统计信息

SOA 记录里的序列号很实用:改了记录后,看权威服务器的 SOA 序列号是否增加,就知道变更有没有生效。

四、nslookup 与 Windows 上的工具

nslookup 是另一个常用工具,Windows 上默认自带:

nslookup www.example.com
nslookup www.example.com 223.5.5.5      # 指定 DNS 服务器
nslookup -type=AAAA www.example.com
nslookup -type=NS example.com
nslookup -debug www.example.com         # 详细输出

Windows PowerShell 上更现代的选择:

Resolve-DnsName www.example.com
Resolve-DnsName www.example.com -Type AAAA
Resolve-DnsName www.example.com -Server 223.5.5.5
Clear-DnsClientCache                     # 清本地缓存
Get-DnsClientCache                       # 看缓存内容
ipconfig /displaydns                     # 命令行看缓存
ipconfig /flushdns                       # 清缓存

注意 nslookup 的一个行为特点:它在查询失败时可能返回"不存在的域",即使是超时造成的。判断时要结合多个工具的结果,不要只看 nslookup 一句话。

五、resolv.conf 与 systemd-resolved 的坑

这是 Linux 服务器上最常见的 DNS 配置困惑来源。

/etc/resolv.conf 老是被覆盖

你可能手动改了 /etc/resolv.conf,重启或重启网络后又变回去了。因为有多个程序都在管理它:

  • NetworkManager:按连接配置写入
  • systemd-resolved:把自己作为 stub 监听在 127.0.0.53
  • cloud-init:云服务器初始化时会写
  • dhclient / resolvconf:DHCP 客户端会更新

先确认它是不是符号链接:

ls -la /etc/resolv.conf
cat /etc/resolv.conf

如果看到:

nameserver 127.0.0.53
options edns0 trust-ad
search .

说明本机在用 systemd-resolved 做 stub resolver,真正的 DNS 服务器配置不在 resolv.conf 里。

systemd-resolved 的诊断命令

resolvectl status                    # 查看每个接口的 DNS 配置(新版本)
resolvectl query www.example.com     # 用它查询
resolvectl statistics                # 统计信息,看缓存命中与失败数
resolvectl flush-caches              # 清缓存

# 老版本命令(仍广泛可用)
systemd-resolve --status
systemd-resolve --statistics
systemd-resolve --flush-caches

resolvectl status 的输出里会分别列出 Global(全局 DNS)和每个网卡的 DNS 设置。注意实际生效的是当前网卡的配置,改了 Global 但网卡上有自己的 DNS 时,可能走的是网卡那个。

修改方式:

# NetworkManager 管理时
nmcli con show
nmcli con mod eth0 ipv4.dns "223.5.5.5 119.29.29.29"
nmcli con mod eth0 ipv6.dns "2400:3200::1"
nmcli con up eth0

# 或改 /etc/systemd/resolved.conf 的全局配置
[Resolve]
DNS=223.5.5.5 119.29.29.29
FallbackDNS=8.8.8.8
sudo systemctl restart systemd-resolved
resolvectl status

不推荐的做法是用 chattr +i /etc/resolv.conf 锁住文件。 这会导致网络管理服务报错,且后续排查时更难理解发生了什么。正确做法是去配置真正管理它的那个服务。

Ubuntu 上如果用的是 netplan,DNS 配置写在 yaml 里:

network:
  version: 2
  ethernets:
    eth0:
      nameservers:
        addresses: [223.5.5.5, 119.29.29.29]
sudo netplan try
sudo netplan apply

用系统解析器验证

getent hosts www.example.com     # 走完整的系统解析路径(nsswitch + hosts + DNS)

getent 的结果和 dig 不一致时,说明问题在系统的解析路径上(hosts 文件、nsswitch 顺序、或 stub resolver 配置),而不是 DNS 服务器本身。

六、常见失败原因清单

原因 典型表现 诊断方法
记录写错或没配 NXDOMAIN dig +trace、dig @权威 NS
域名未实名/未备案被暂停 境内 DNS 解析失败,境外正常或也失败 whois 查域名状态
权威 DNS 服务器故障 +trace 到权威段无响应 dig example.com NS 逐个测
TTL 缓存未过期 改了记录但部分地区还是旧值 查返回的 TTL 值
DNSSEC 校验失败 SERVFAIL dig +dnssec、查 DS 记录
本地 DNS 污染/劫持 返回错误 IP 多 DNS 对比、+trace 对比
resolv.conf 被覆盖 改了配置重启又回去 ls -la /etc/resolv.conf
systemd-resolved 配置错 部分接口不通 resolvectl status
防火墙拦 53 解析超时 tcpdump port 53
UDP 53 限速/丢包 时好时坏 dig +tcp 对比
应用自带缓存 系统解析正常但应用失败 重启应用、清应用缓存

域名状态被暂停

这是国内域名特有的问题,且不常被想到。域名如果未完成实名认证、或涉及备案问题,注册局会设置 clientHold 或 serverHold 状态,该域名会被全局停止解析。

whois example.com | grep -i -E 'status|hold'

正常状态应包含 ok 或 clientTransferProhibited 这类正常标记;出现 clientHold、serverHold 就说明被暂停了。解决方式是去注册商处完成实名认证或处理违规,处理完成后状态恢复,解析才会恢复。

DNSSEC 问题

DNSSEC 通过数字签名保证解析结果未被篡改,但配置错误会导致整条链校验失败,表现为 SERVFAIL。

dig +dnssec www.example.com
dig example.com DS +short          # 看上级是否发布了 DS 记录

常见的失败场景:换了域名解析服务商,但注册商处还留着旧服务商的 DS 记录;或者解析商开了 DNSSEC 但注册商没同步 DS。结果是签名链断裂。

处理:要么在注册商处更新或删除 DS 记录,要么先在解析商处关闭 DNSSEC 恢复服务,再慢慢修正。

风险提示:操作 DNSSEC 记录有导致域名完全不可解析的风险,且不熟悉时容易改错。建议先在测试域名上验证,或者联系解析服务商的技术支持协助。修改前记录当前 DS 记录的完整内容以便回滚。

防火墙与 53 端口

sudo tcpdump -i eth0 -nn 'port 53'
sudo iptables -L -n -v | grep -E '53|domain'

要同时放行 UDP 53 和 TCP 53。 很多人只放了 UDP,导致大响应(超过 512 字节,启用 DNSSEC 后很常见)无法回落 TCP,表现为"大部分域名能解析,某些域名不行"。

云安全组也要检查出方向的 UDP/TCP 53。

七、用 hosts 文件做临时验证

当你怀疑是 DNS 问题、需要快速恢复业务时,hosts 文件是最直接的临时方案。

Linux:

sudo vi /etc/hosts
# 添加一行
1.2.3.4    www.example.com
getent hosts www.example.com     # 验证是否生效

Windows(需要管理员权限编辑):

C:\Windows\System32\drivers\etc\hosts

添加同样格式的一行,然后执行 ipconfig /flushdns 清缓存。

hosts 的几个注意点:

  • 这是临时方案,只在本机生效,其他机器和用户仍然解析失败
  • 加之前先用 dig +trace 或 dig @公共DNS 确认正确的 IP,不要凭记忆填
  • 问题修好后一定要删掉,否则将来 IP 变更时会出现"其他人都正常、就这台机器连到旧 IP"的诡异故障
  • 服务器数量多时,改 hosts 不现实,应该修 DNS 本身

八、解决与预防

排查顺序建议

# 1. 确认本地解析结果
getent hosts www.example.com
dig www.example.com A +short

# 2. 换个公共 DNS 对比
dig @223.5.5.5 www.example.com A +short
dig @119.29.29.29 www.example.com A +short
dig @8.8.8.8 www.example.com A +short

# 3. 追踪完整解析链
dig +trace www.example.com

# 4. 直接问权威服务器
dig @权威NS www.example.com A

# 5. 检查域名状态
whois example.com | grep -i status

# 6. 检查本机解析器
resolvectl status
cat /etc/resolv.conf

# 7. 抓包确认 53 端口
sudo tcpdump -i eth0 -nn 'port 53'

预防措施

配置两个以上的 DNS 服务器。 主用 223.5.5.5,备用 119.29.29.29 或 8.8.8.8。单一 DNS 故障是常见事故。

变更解析前先把 TTL 调小。 提前一天把 TTL 改成 300 或 600,变更时就能快速生效,改完再调回大值减少查询压力。这是做迁移和切换的标准动作。

监控解析结果。 从多个地区、多个运营商定期解析关键域名,比对结果是否与预期一致。这能在用户投诉前发现污染或配置错误。

关键服务考虑 IP 直连或保留备用域名。 对一些关键的内部依赖,可以在配置里保留 IP 兜底,或者准备一个不同后缀的备用域名。

记录权威 NS 清单并定期检查可达性。 用 dig example.com NS +short 拿到所有权威服务器,逐个测试它们是否都能正常应答。部分 NS 不可达时平时没感觉,一旦其他 NS 故障就会放大问题。

不要过度依赖 /etc/hosts 做长期方案。 它会掩盖问题,且在多台机器间难以同步。

常见问题

改了解析记录多久生效?

取决于原记录的 TTL。如果 TTL 是 3600 秒,最坏情况要一小时各级缓存才过期。各地运营商的递归服务器刷新节奏不同,所以会表现为"部分地区已生效、部分地区还是旧的"。下次变更记得提前把 TTL 调小。

为什么境外 DNS 能解析、境内不行?

几种可能:域名被设置了 hold 状态(未实名或未备案);境内递归 DNS 缓存了旧结果;或者域名解析服务商在境内没有节点导致响应慢。先用 whois 查域名状态,再用 dig +trace 看权威段的应答。

ping 提示 unknown host,但 IP 能 ping 通,是什么问题?

典型的 DNS 问题,网络层正常。按排查顺序走:dig 看返回码、换公共 DNS 对比、dig +trace 追链、检查 /etc/resolv.conf 和 resolvectl status。

systemd-resolved 和 /etc/resolv.conf 到底是什么关系?

systemd-resolved 提供一个本地 stub 解析器(通常监听 127.0.0.53),并把 /etc/resolv.conf 指向它。所以你在 resolv.conf 里只看到 127.0.0.53,真正的上游 DNS 要用 resolvectl status 看。直接改 resolv.conf 会在网络重启后被覆盖。

怎么判断是不是 DNS 被劫持?

对比 dig +trace(权威真实答案)和直接 dig(递归服务器答案)的结果。如果两者 IP 不同,说明递归环节有问题。再换几个公共 DNS 对比,如果只有默认那个返回错误结果,就可以确定是它的问题。

服务器上要不要配 8.8.8.8?

境内服务器不建议把它作为首选。境外 DNS 在境内的响应速度和稳定性都不如境内公共 DNS,且部分情况下会被干扰。建议首选 223.5.5.5 或 119.29.29.29,境外 DNS 作为备用或者排查对比时使用。

清 DNS 缓存有用吗?

有用,但只清本机那一层。systemd-resolved 用 resolvectl flush-caches,Windows 用 ipconfig /flushdns,应用自身的缓存要重启应用。运营商递归服务器的缓存你清不掉,只能等 TTL 过期。

总结

  • 理解解析链是排查的基础:应用缓存 → hosts → stub resolver → 递归 DNS → 根 → TLD → 权威。dig +trace 拿到的是权威真实答案,直接 dig 拿到的是递归服务器的答案,两者不一致就说明问题在递归环节(缓存、污染或劫持)。
  • 先看返回码再动手:NXDOMAIN 是记录不存在或写错,SERVFAIL 多是 DNSSEC 或权威服务器问题,REFUSED 是递归被拒,超时则是网络或 53 端口问题。
  • 多 DNS 对比是最快的定位手段:用 223.5.5.5、119.29.29.29、114.114.114.114、8.8.8.8 分别查一遍,一致说明 DNS 正常,只有本地那个不同就是本地 DNS 的问题。
  • systemd-resolved 是 Linux 上最大的困惑源:/etc/resolv.conf 里的 127.0.0.53 只是 stub,真实配置要用 resolvectl status 看;改配置要改 NetworkManager、netplan 或 resolved.conf,不要用 chattr +i 锁文件。
  • 境内域名特有的坑是状态被暂停(clientHold/serverHold,多因未实名或未备案),用 whois 域名 | grep -i status 检查;DNSSEC 配置错误会表现为 SERVFAIL,紧急处理是先在解析商处关闭再慢慢修正,改前务必记录原 DS 内容。
  • 防火墙要同时放行 UDP 53 和 TCP 53,只放 UDP 会导致大响应无法回落,表现为"部分域名解析不了";怀疑 UDP 被限速时用 dig +tcp 对比验证。
  • hosts 文件只作为临时止血手段,用完必须删除;长期预防靠多 DNS 冗余、变更前提早调小 TTL、以及从多地定期监控解析结果。