DNS 配置错误怎么修复?服务器 DNS 异常的排查步骤
DNS 配置错误的典型表现是:ping IP 地址通,ping 域名却报找不到主机。修复按五步走:先确认报错确实来自域名解析,再看系统实际在用的 DNS 地址,换一个 DNS 对比查询,检查 53 端口有没有被防火墙拦截,最后排除 hosts 文件、nsswitch 和本地缓存的干扰。
DNS 配置错误怎么修复?先确认症状:服务器能 ping 通外网 IP,却 ping 不通域名,yum、apt、curl 都报无法解析主机,这就是域名解析出了问题,而不是网络断了。排查按五步走:一看报错,确认是解析失败;二看系统实际在用哪个 DNS 地址;三换一个 DNS 对比查询,判断坏的是 DNS 服务器还是本机;四查 53 端口有没有被防火墙或安全组拦截;五排除 hosts 文件、nsswitch 和缓存的干扰。多数 DNS 异常在前三步就能定位,常见原因是 DNS 地址写错、内网 DNS 宕机、防火墙拦截 53 端口和 systemd-resolved 冲突。下面给出每一步在 Linux 和 Windows 上的命令,最后是原因对照表。
第一步:确认是不是 DNS 的问题(IP 通、域名不通)
用三条命令把“网络不通”和“解析不通”分开:
ping -c 3 223.5.5.5 # 外网 IP 能通,说明网卡、网关、路由都正常
ping -c 3 www.example.com # 域名不通,问题在解析
curl -sI http://203.0.113.10 # 禁 ping 时用 TCP 代替,IP 换成一个确定能访问的网站地址
第一条通、第二条报错,就可以把注意力集中到 DNS 上;第一条也不通,先查网络本身,DNS 配置改得再对也没用。
不同程序报出的错误文字不一样,但能看出解析卡在哪种状态:
| 报错 | 出现在 | 说明 |
|---|---|---|
Temporary failure in name resolution |
ping、ssh 等调用系统解析器的程序 | 没拿到任何 DNS 应答:DNS 地址不可达、超时,或者根本没配置 |
Name or service not known |
同上 | 拿到了“不存在”的结论:域名拼错、DNS 回答 NXDOMAIN,或 nsswitch 里没有启用 dns |
Could not resolve host、Couldn't resolve host name |
curl、yum、dnf | 解析失败,具体原因用前两种区分 |
Temporary failure resolving 'archive.ubuntu.com' |
apt | 与第一行相同,DNS 没有应答 |
Ping 请求找不到主机 |
Windows 的 ping | 系统解析失败 |
DNS request timed out |
nslookup | 指定的 DNS 服务器没有应答 |
Non-existent domain |
nslookup | DNS 服务器明确回答“域名不存在” |
DNS_PROBE_FINISHED_NXDOMAIN |
Chrome 等浏览器 | 解析失败或域名不存在 |
“没有应答”和“回答不存在”是两类问题:前者多半是 DNS 地址或网络路径的问题,后者要么是域名写错,要么是这台 DNS 给出的结果本身有问题。
第二步:查看系统实际在用的 DNS 地址
Linux 上先看 resolv.conf 是什么、指向哪里:
ls -l /etc/resolv.conf # 是普通文件还是链接
cat /etc/resolv.conf
resolvectl status 2>/dev/null | grep -E "Current DNS|DNS Servers"
nmcli device show 2>/dev/null | grep -i dns
逐项对照下面这些情况,任何一条成立,基本就找到原因了:
- 没有任何 nameserver 行。glibc 此时默认去问本机 127.0.0.1,本机没跑 DNS 服务,所有查询都失败。
- cat 报 No such file or directory。resolv.conf 是一个断掉的链接,常见于停用了 systemd-resolved,但链接还指向它运行时才有的文件。
- 只有
nameserver 127.0.0.53。这是 systemd-resolved 的本地入口,要再确认systemctl is-active systemd-resolved输出 active,并用resolvectl status看它背后真正的上游 DNS。 - 地址本身不对。少写或多写了一位、填成了不提供 DNS 服务的网关地址、照搬了别的机房的模板,这类错误肉眼看很容易漏过,要和机房给出的 DNS 地址逐位核对。
- 只有一个地址,而那台 DNS 正好故障。
Windows 上执行 ipconfig /all,看每块网卡的“DNS 服务器”一行,或者用 PowerShell 只列出配置了 DNS 的网卡:
ipconfig /all
Get-DnsClientServerAddress | Where-Object { $_.ServerAddresses } |
Select-Object InterfaceAlias, AddressFamily, ServerAddresses
几个 Windows 上的典型现象:DNS 显示为 fec0:0:0:ffff::1 这类地址,是系统在 IPv6 没有配置 DNS 时填的占位值,不是真正的服务器;网卡显示“DHCP 已启用”,说明 DNS 是 DHCP 下发的,手工改过后可能又被下发的值覆盖;多块网卡都填了 DNS,其中内网卡上的 DNS 已经失效,也会让解析时好时坏。
第三步:换一个 DNS 对比查询,判断坏在哪里
用同一个域名,分别问“系统配置的 DNS”“一个公共 DNS”和“系统解析流程”,三个结果一对比,故障位置就清楚了。
dig www.example.com +tries=1 +time=2 # 问 resolv.conf 里的第一个 DNS
dig @223.5.5.5 www.example.com +tries=1 +time=2 # 指定一个公共 DNS
getent hosts www.example.com # 走系统解析流程:hosts、nsswitch、缓存
nslookup www.example.com # 问系统配置的第一个 DNS
nslookup www.example.com 223.5.5.5 # 指定公共 DNS
Resolve-DnsName www.example.com # 走系统解析流程,含 hosts 文件与本机缓存
dig 和 nslookup 在 RHEL 系由 bind-utils 软件包提供,在 Debian 系由 dnsutils 提供,命令不存在时先安装。对照下表下结论:
| 配置的 DNS | 公共 DNS | 系统解析流程 | 结论 | 去哪一步 |
|---|---|---|---|---|
| 超时 | 正常 | 失败 | 配置的 DNS 地址写错了,或者那台 DNS 服务器故障 | 改正地址,或修复、更换 DNS |
| 超时 | 超时 | 失败 | 到任何 DNS 的 53 端口都不通 | 第四步 |
| 正常 | 正常 | 失败 | DNS 没问题,问题在本机的解析流程 | 第五步 |
| 正常 | 正常 | 返回了不同的地址 | hosts 文件或缓存里有旧条目 | 第五步 |
| status: REFUSED | 正常 | 失败 | 那台 DNS 拒绝为你递归查询,通常是访问控制没包含本机网段 | 联系 DNS 管理员 |
| SERVFAIL 或 NXDOMAIN | 同样失败 | 失败 | 域名本身有问题 | 用 dig +trace 追查 |
dig 输出里 status: 后面的值很关键:NOERROR 是正常;NXDOMAIN 是域名不存在;SERVFAIL 是递归服务器没能拿到可信的结果;REFUSED 是服务器收到了查询但拒绝回答。看到 REFUSED 反而说明网络是通的,问题在对方的配置,比如内网 DNS 的递归访问控制(BIND 的 allow-recursion)没有包含这台服务器所在的网段。
第四步:检查 53 端口有没有被防火墙拦截
DNS 查询平时走 UDP 53,应答较大时改走 TCP 53。分别测两种协议,能直接判断拦的是哪一种:
dig @223.5.5.5 www.example.com +tries=1 +time=2 # UDP
dig +tcp @223.5.5.5 www.example.com +tries=1 +time=2 # TCP
nc -zv -w 3 223.5.5.5 53 # 只测 TCP 53 能否建立连接
TCP 正常而 UDP 超时,说明 UDP 53 被拦;两者都超时,说明到 DNS 服务器的 53 端口整体不通。要知道包是没发出去还是没回来,抓包看一眼:
tcpdump -nni any port 53 # 在另一个窗口执行查询,观察有没有请求发出、有没有应答回来
只看到发出的请求、没有应答,问题在本机之外:云安全组的出方向规则、机房只允许访问指定的 DNS、上游的 ACL。连请求都看不到,问题在本机:出方向防火墙规则,或解析器根本没有向这个地址发包。
本机防火墙这样查:
iptables -S OUTPUT # 默认策略是 DROP 时,要有放行 53 的规则
iptables -S INPUT | grep -i established # 入方向要放行已建立连接的回包
nft list ruleset | grep -n "dport 53"
Get-NetFirewallProfile | Select-Object Name, DefaultOutboundAction # Block 表示默认阻止出站
出方向默认拒绝的服务器,放行 DNS 要写两类规则:出方向允许 UDP 和 TCP 的 53,入方向允许已建立连接的回包。以 iptables 为例:
iptables -I OUTPUT -p udp --dport 53 -j ACCEPT
iptables -I OUTPUT -p tcp --dport 53 -j ACCEPT
iptables -I INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
规则确认有效后,按系统的方式保存,否则重启后丢失。只放行了 UDP 而没放行 TCP 53,平时看不出问题,遇到应答较大的域名(记录很多、开启了 DNSSEC)才会偶发失败,这类问题最难查,两种协议应一起放行。
第五步:排除 hosts 文件、nsswitch 与缓存
dig 和 nslookup 直接与 DNS 服务器对话,而程序解析域名要先经过本机的一套流程。DNS 查询正常、程序还是报错,就看这三处。
hosts 文件。里面写死的条目优先于 DNS,测试时临时加的记录忘了删,就会让某个域名一直指向旧地址:
grep -vE '^\s*(#|$)' /etc/hosts
Get-Content C:\Windows\System32\drivers\etc\hosts | Where-Object { $_ -notmatch '^\s*#' -and $_.Trim() }
nsswitch.conf(仅 Linux)。它决定解析时按什么顺序查哪些来源:
grep '^hosts' /etc/nsswitch.conf
# 正常应类似:hosts: files dns myhostname
这一行里没有 dns,系统就只查 hosts 文件,dig 查询一切正常、所有程序却都解析失败,正是表格里“DNS 正常、系统解析流程失败”的典型原因。精简过的容器镜像和被安全加固脚本改过的系统偶尔会出现这种情况,把 dns 加回去即可,不需要重启。
缓存。修好之后,旧的失败结果可能还留在缓存里:Linux 上使用 systemd-resolved 的执行 resolvectl flush-caches,使用 nscd 的执行 nscd -i hosts;Windows 先用 ipconfig /displaydns | findstr example 看缓存里有没有这个域名,再用 ipconfig /flushdns 清掉。注意失败的查询结果也会被缓存一段时间,修复后不清缓存,会误以为没修好。Java、Nginx 这类自己缓存解析结果的程序,要重启或重载才会重新解析。
systemd-resolved 冲突与 DNS 异常常见原因对照表
Ubuntu 18.04 及之后的版本、Fedora 33 及之后的版本默认启用 systemd-resolved,其他发行版也可能手动启用了它。它会带来几种特有的故障:
- 服务没在运行。resolv.conf 里只有 127.0.0.53,而 systemd-resolved 被停用了,所有查询都发给一个没人监听的地址。执行
systemctl enable --now systemd-resolved恢复;如果确实不想用它,就把 resolv.conf 换成写有真实 DNS 地址的普通文件。 - 与本地 DNS 服务抢 53 端口。在同一台机器上装 dnsmasq 等本地 DNS 服务、并让它监听所有地址的 53 端口时,会和已经占用 127.0.0.53:53 的 systemd-resolved 冲突,新服务启动时报 Address already in use。用
ss -lunp 'sport = :53'确认占用者,在/etc/systemd/resolved.conf里设置DNSStubListener=no后重启它,再把 resolv.conf 指向新装的 DNS 服务。 - 查询被别的网卡“抢走”。服务器接了 VPN 或第二块网卡,那块网卡上的 DNS 会参与解析,某些域名的查询被发到了错误的 DNS。
resolvectl status能看到每块网卡各自的 DNS,resolvectl query www.example.com会显示这次结果是经由哪块网卡、用了多长时间拿到的。 - 想绕过本地入口。需要让程序直接使用上游 DNS 时,执行
ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf,这个文件里列出的是 systemd-resolved 当前使用的真实上游地址。
把常见原因汇总如下,排查时可以按“典型表现”一列对号入座:
| 原因 | 典型表现 | 怎么确认 | 怎么修复 |
|---|---|---|---|
| DNS 地址写错 | 所有域名超时 | 对该地址 dig 超时,换公共 DNS 正常 | 改成机房提供的正确地址 |
| 手工配置被覆盖 | 修好后重启又坏 | resolv.conf 开头的生成注释,网卡的 DHCP 状态 | 到 NetworkManager、netplan 或 DHCP 的源头修改 |
| 内网 DNS 宕机 | 同网段多台服务器同时解析失败 | 对内网 DNS dig 超时,DNS 服务器上服务状态异常 | 恢复服务,并部署第二台互为备份 |
| 内网 DNS 拒绝递归 | status: REFUSED | dig 输出 | 把服务器网段加入允许递归的范围 |
| 防火墙或安全组拦截 53 | UDP 超时,TCP 可能正常 | dig 与 dig +tcp 对比,tcpdump | 放行出方向 UDP、TCP 53 和回包 |
| systemd-resolved 未运行 | 只有 127.0.0.53 且无应答 | systemctl is-active systemd-resolved |
启动服务,或改用普通 resolv.conf |
| 53 端口被争用 | 本地 DNS 服务启动失败 | ss -lunp 'sport = :53' |
设置 DNSStubListener=no |
| hosts 残留条目 | 单个域名指向旧地址 | getent 与 dig 的结果不同 | 删除条目并清缓存 |
| nsswitch 缺少 dns | dig 正常,程序全部失败 | grep '^hosts' /etc/nsswitch.conf |
把 dns 加回去 |
| 不可达的 IPv6 DNS 排在前面 | 每次解析都要多等几秒才成功 | 看 resolv.conf 的顺序,time getent hosts |
调整顺序或删除该地址 |
| 系统时间偏差太大 | 开启了 DNSSEC 校验的本机解析器返回 SERVFAIL | date 与实际时间对比 |
校准时间 |
在管理系统里怎么落地
“DNS 地址写错”和“手工配置被覆盖”是最常见的两类原因,根源都是服务器上该填什么没有一个可以核对的依据。Toplink DCIM 的 IP 地址管理 中,每个地址段除了网段、网关和 VLAN,还填写了两个 DNS 地址:排查时拿服务器的 resolv.conf 或 ipconfig /all 输出和这条记录逐位对照,地址写错、照搬了别的机房模板,一眼就能看出来;同一个段的服务器同时出现解析失败时,也能马上确认它们共用的是哪台 DNS。如果排查到第一步就发现连外网 IP 都不通,问题在网络本身,可以在 交换机管理 里查看这台服务器所在的交换机端口是否开启、VLAN 是否正确,或者在浏览器里打开交换机终端继续排查。
常见问题
电脑 DNS 异常上不了网怎么办?
先执行 ipconfig /flushdns 清缓存;再到网卡属性里把 DNS 改为手动填写,例如 223.5.5.5 和 119.29.29.29。仍然不行,重启路由器,并检查代理软件或安全软件是否接管了网络;网络组件被改坏时,管理员身份执行 netsh winsock reset 后重启电脑。
nslookup 显示 Server: UnKnown,是 DNS 出问题了吗?
不是。UnKnown 只表示 nslookup 没能反查到这台 DNS 服务器 IP 对应的名字(没有 PTR 记录),下面能正常返回域名的地址,解析就是正常的。
为什么只有一个域名解析失败,其他域名都正常?
多半是这个域名自己出了问题,比如权威服务器故障、记录被删、DNSSEC 签名过期,这时换公共 DNS 通常也查不到。用 dig +trace 域名 看查询卡在哪一级,再联系域名的管理方。