linux本地dns解析优先级由/etc/nsswitch.conf中hosts行决定,默认files dns表示先查/etc/hosts再查dns;修改后仅新进程生效,且需注意systemd-resolved覆盖、/etc/hosts格式规范及应用层绕过等问题。

Linux 本地 DNS 解析优先级怎么定
Linux 不是“配置了 /etc/resolv.conf 就一定走它”,解析顺序由 nsswitch.conf 决定。默认情况下,hosts: files dns 表示先查 /etc/hosts,再查 DNS;如果改成 hosts: dns files,反而会让 /etc/hosts 失效——这是很多人改完 DNS 还不生效的根源。
- 检查顺序:运行
cat /etc/nsswitch.conf | grep hosts - 修改后无需重启服务,但已有进程(如已启动的 curl、wget)不会自动重读,新终端或新进程才生效
- systemd-resolved 或 NetworkManager 管理的系统,
/etc/resolv.conf可能是软链接,直接改会被覆盖
/etc/hosts 里写错格式会导致整行失效
/etc/hosts 看似简单,但空格、注释、IPv6 地址混用极易出错。比如用 Tab 替代空格、在 IP 后加多余空格、或把注释写在行末但没加 #,都会让该行被完全忽略,且系统不报错。
- 必须用 一个或多个空格或制表符 分隔 IP 和主机名,推荐只用空格
- 每行只能有一个 IP,不能写
127.0.0.1 a.com b.com—— 后续域名不会被解析 - IPv6 地址要用方括号?不用。
::1直接写,但别写成[::1],否则解析失败 - 示例正确写法:
127.0.0.1 example.local,错误写法:127.0.0.1 example.local # test(末尾空格+无#会截断)
systemd-resolved 覆盖 resolv.conf 是常态,不是异常
Ubuntu 18.04+、Fedora、Debian 11+ 默认启用 systemd-resolved,它会把 /etc/resolv.conf 指向自己的 stub 地址 127.0.0.53。你手动改 /etc/resolv.conf,下次 NetworkManager 重连或 reboot 就恢复——这不是权限问题,是设计如此。
- 查当前真实 DNS:运行
resolvectl status,看 “DNS Servers” 下的地址 - 临时改 DNS(重启后失效):
resolvectl dns eth0 8.8.8.8 - 永久改法:编辑
/etc/systemd/resolved.conf,取消注释DNS=行并填值,再执行sudo systemctl restart systemd-resolved - 不想用 resolved?可禁用:
sudo systemctl disable --now systemd-resolved,再删软链接、重建/etc/resolv.conf
hosts 和 DNS 冲突时,谁赢取决于 nsswitch + 应用行为
即使 /etc/hosts 有记录,某些程序(如 Chrome、Firefox、curl with --resolve)可能绕过系统解析器,直接走自己逻辑;而 ping、ssh、git 通常遵守 nsswitch.conf。更隐蔽的是 glibc 缓存:改完 /etc/hosts 后,旧进程可能还在用缓存结果。
- 验证是否真走了 hosts:用
getent hosts example.local(它严格按 nsswitch 执行) - 清 glibc 缓存(部分系统支持):
sudo systemd-resolve --flush-caches或重启systemd-resolved - 排查应用特例:Chrome 访问
chrome://net-internals/#dns查 DNS 日志;curl 加-v看 Host 头和实际连接 IP - 不要依赖
nslookup测试 hosts —— 它只查 DNS,根本不读/etc/hosts
真正麻烦的从来不是“怎么写”,而是“谁在读、什么时候读、读到哪一层”。/etc/hosts 生效与否,resolv.conf 是否被接管,nsswitch.conf 的顺序,glibc 的缓存,还有应用自身的解析策略——四层叠加,漏掉任何一层,配置就看起来“没用”。











