IP、DNS与域名解析:从hosts配置到问题排查实战
上个月给一套本地开发环境配Nginx多站点我想用dev.project.com、test.project.com这类域名来区分访问于是顺手改了 hosts 文件把域名指向虚拟机的 IP。结果浏览器一敲连接超时ping 域名也超时。折腾了半小时最后发现虚拟机的 IP 在重启后变了我 hosts 里写的还是旧地址。这个错误确实低级但它把 IP、DNS、域名三者之间的关系暴露得很彻底域名给你一个方便记忆的名字DNS负责把名字翻译成IPIP才是网络上真正用来找设备的门牌号。你只要其中一个环节对不上访问就失败。这篇文章我就围绕这三者的关系展开结合我实际踩过的坑和排查思路把输入一个域名到底发生了什么讲清楚也把 IP 冲突、DNS 配置失效、解析不生效这些高频问题一起梳理一遍。1. 那台改了Hosts却访问不了的虚拟机把三者的关系全暴露了先回到开头那个案例。我本地起了三台虚拟机分别跑不同的 Nginx 站点为了方便区分想用dev.project.com、test.project.com这类域名访问。理论上只要在宿主机 hosts 文件里写一句192.168.1.50 dev.project.com浏览器输入域名就会直接走 hosts 的映射跳过 DNS 查询。但我忽略了虚拟机是 DHCP 分配的地址重启之后可能换 IP。那次正好虚拟机从192.168.1.50变成了192.168.1.60hosts 里还指向旧地址自然连不上。这个案例看着简单但它把三者的分工讲得很明白域名是给人用的名字IP 是网络传输时真正用来定位的地址hosts 文件和 DNS 系统都是负责把名字翻译成地址的。你理解了这个三角关系后面所有排障思路都围绕它展开。1.1 IP是设备在网络里唯一的门牌号IP 地址是设备在网络中的定位标识。IPv4 是 32 位的数字写成点分十进制的样子比如192.168.1.50IPv6 是 128 位写成更长的十六进制串比如240e:...这种。你可以把 IP 当成门牌号快递员要找到你家必须知道门牌号而不是只知道你叫什么名字。这里有个容易混淆的点公网 IP 和私网 IP。公网 IP 是互联网上全局唯一的地址需要向运营商申请或者从云厂商购买。比如你买了一台云服务器它会有一个公网 IP别人通过这个 IP 直接访问你的服务。私网 IP 则是内网使用的保留地址常见三大段10.0.0.0/8、172.16.0.0/12、192.168.0.0/16。家用路由器的设备基本都是私网 IP比如192.168.1.100。这些私网地址通过路由器做 NAT网络地址转换共享一个公网 IP 上网。理解这一点很重要。比如你排查一个设备时通时断的问题第一反应不应该是怀疑 DNS而是先确认它在局域网里的 IP 是不是和别人冲突了。IP 冲突意味着两台设备抢同一个门牌号数据包一会儿发给 A 一会儿发给 B表现就是网络极不稳定。这个后面单独讲。1.2 域名是给人用的名字它本身不带路域名的作用很纯粹让人好记。example.com比203.0.113.10好记无数倍而且 IP 可能变化域名可以保持不变。但域名本身不带任何路由能力它只是一串字符。你在浏览器里输入example.com计算机不能直接用这串字符找目标必须先把域名解析成 IP。之所以说域名本身不带路是因为域名的组织方式是层级化的根域就是那个点在最高层下面是顶级域.com、.org再往下是二级域example.com再往后可以挂子域blog.example.com。每一层的解析都靠对应的域名服务器负责。域名的注册、续费、DNS 服务器设置都围绕这套层级体系展开。你注册了一个域名实际上是在某个顶级域下面申请了一个二级域名的使用权然后自己指定负责解析的 NS 服务器。1.3 DNS是负责把名字翻译成门牌号的查号台DNSDomain Name System解决的是名字到地址的翻译问题。你可以把它理解成电话本你知道对方的名字但找不到电话于是翻电话本查号码。DNS 就是这个分布式电话本但它不是一本大书而是一整套分布在全球的层级系统。为什么说是分布式因为如果全世界只有一个 DNS 服务器它根本扛不住所有查询流量也做不到高可用。所以 DNS 数据被分散存放在大量的服务器上根服务器、顶级域服务器、各个域名的权威服务器以及你本机配置的递归解析服务器。查询时按一条链逐级问下去直到拿到最终答案。hosts 文件其实是一个最原始的本地电话本。系统在发起网络请求前会先查这个文件里面有记录就直接用没记录才去找 DNS。这也是为什么改本地开发环境的域名映射时优先用 hosts 而不是配一套 DNS 服务器——简单直接。2. 一次完整的域名解析链路从头到尾是这样的理解了三者关系之后再看输入一个域名到打开网页这个过程你会看到一个清晰的链条。这条链在排障时特别有用任何一环出问题故障表现都不一样。先记住一句话解析是分层的缓存无处不在。2.1 从浏览器输入地址到发出请求经历了什么以访问https://www.example.com为例。你在浏览器按下回车浏览器不会直接把请求发出去而是先拿到www.example.com对应的 IP。完整流程大致分这几步浏览器查自己的 DNS 缓存。现代浏览器都会缓存解析结果Chrome 可以访问chrome://net-internals/#dns查看。浏览器没命中交给操作系统查 DNS 缓存。操作系统缓存也没有查 hosts 文件。Windows 在C:\Windows\System32\drivers\etc\hostsLinux/macOS 在/etc/hosts。命中则直接返回 IP。hosts 没有系统把请求交给本地配置的 DNS 服务器递归解析器。这个值通常来自路由器下发的 DHCP 配置也可能是你手动设置的。递归解析器开始工作它先查自己的缓存没有就向根服务器问.com的顶级域服务器是谁拿到地址后再问.com服务器example.com的权威服务器是谁最后向example.com的权威服务器询问www的 A 记录。最终拿到www.example.com对应的 IP原路返回给系统系统再交给浏览器。浏览器拿到 IP 后通过 HTTP 协议发起连接请求后面才是 TCP 三次握手、TLS 握手这些事。这里有个术语需要分清递归查询和迭代查询。你的电脑向递归解析器发起的是一次性请求你帮我查完再告诉我结果这叫递归查询。而递归解析器向根服务器、顶级域服务器、权威服务器逐级询问的过程中每一步都是被告知往下找谁这叫迭代查询。很多教程没说清楚导致排障时不知道问题可能出现在哪个环节。2.2 TTL与缓存改了解析记录却迟迟不生效的真相TTLTime To Live是 DNS 返回记录里的一个参数表示这条记录允许被缓存多少秒。常见值有 60010分钟、36001小时也有短的如 60 秒。它决定了当你修改了一条解析记录旧的记录要多久才会在别人那里过期。很多人改完 DNS 记录等了十分钟刷新还是旧 IP就以为没生效其实是缓存还没过期。浏览器有缓存操作系统有缓存本地递归解析器也有缓存甚至中间路由器可能也有缓存。如果 TTL 设的是 3600 秒理论上最长要等一小时全世界访问你的域名的客户端才会统一拿到新解析结果。所以专业做法是如果你预计要改服务器 IP提前几小时把 TTL 调低比如改成 300等旧记录自然过期再变更 IP这样能显著缩短切换过程中的新旧 IP 共存期。强制刷新本机缓存的命令也很常用。Windows 上执行ipconfig /flushdnsLinux 上如果用的是 systemd-resolvedresolvectl flush-caches但注意刷新的是本机缓存你控制不了对方的递归解析器。对方网络里运营商 DNS 有缓存你就只能等。这也是我一直跟同事强调的DNS 生效时间不归你管提前规划 TTL 才是正途。2.3 A、AAAA、CNAME、MX记录类型与使用场景对照排障和配置解析时经常要看域名用的是哪种记录。记录类型不同查询的侧重点也不同。我整理了一张对照表记录类型作用典型场景A域名指向 IPv4 地址最常见www.example.com指向203.0.113.10AAAA域名指向 IPv6 地址站点支持 IPv6 时必须配置CNAME域名别名指向另一个域名把www.example.com别名到example.com或者指向 CDN 分配的域名MX邮件交换记录指定邮件服务器收发邮件时其他邮件服务器靠它找到目标NS指定该域名由哪台 DNS 服务器负责域名注册后要设置 NS 指向你的 DNS 托管商TXT文本记录常用于验证和 SPF 反垃圾邮件验证域名所有权、配置 SPF/DKIMPTR反向解析IP 指向域名邮件服务器做反查防止伪造时比较常见选型时有个原则如果你有固定 IP直接用 A 记录如果目标可能变或者你要对接 CDN、负载均衡CNAME 更省事因为你可以只改 CNAME 指向的源头不用改业务域名的记录。邮件相关的检查优先看 MX 和 TXT很多发信被拒的问题都出在 SPF 记录配置不全。3. 排查实战IP冲突、Linux DNS失效、解析结果异常怎么处理理论清楚了排障才有底气。我把日常遇到最多的三类问题展开讲每一类都按现象 → 定位 → 解决的思路走。3.1 IP冲突从设备时通时断到找到肇事机器的全过程IP 冲突在局域网里太常见了。典型现象某台设备网络一会儿通一会儿断ping 网关丢包严重偶尔远程连接直接被重置。如果你用ping -tWindows或ping IPLinux 持续模式去 ping 一台指定 IP 的设备会发现响应时有时无。这说明那个 IP 可能有多个设备在抢。排查步骤按下面走确认自己的 IP 和网关。Windows 执行ipconfig /allLinux 执行ip a记下本机 IP 和默认网关。用另一台设备持续 ping 冲突的那个 IP。比如你怀疑192.168.1.50冲突就换一台机器执行ping 192.168.1.50 -t。断开当前设备的网络连接拔网线或关 Wi-Fi继续观察 ping 结果。如果 ping 仍然有响应说明192.168.1.50确实被其他设备占用了。执行arp -a查看 ARP 缓存找到192.168.1.50对应的 MAC 地址记下来。根据 MAC 地址定位物理设备。MAC 前三位是 OUI厂商标识可以网上查一下属于哪家厂商更准的做法是登录交换机查看特定端口的学习到的 MAC。找不到交换机管理权限时可以把有嫌疑的设备挨个断开网线再观察arp -a里的 MAC 有没有消失。定位到设备后给它改成静态 IP 绑定或者在路由器 DHCP 里设置地址保留按 MAC 绑定固定 IP。我见过最多的原因是有人图省事给打印机、摄像头、开发板手动配了静态 IP结果和 DHCP 动态分配的地址段重叠了。解决的关键是提前规划DHCP 地址池留一段静态 IP 用另一段避免重叠。路由器管理界面里还应该开启 DHCP 静态绑定保证每台设备拿到的地址稳定。3.2 Ubuntu 22.04改DNS总被还原先搞清楚resolv.conf背后是谁这是一个非常典型的新手问题编辑了/etc/resolv.conf重启网络或者重启系统后又变回原来的内容。原因在于 Ubuntu 18.04 之后默认使用systemd-resolved管理 DNS/etc/resolv.conf不再是普通配置文件而是一个指向/run/systemd/resolve/stub-resolv.conf的软链接。你直接改这个文件相当于改一个系统每次启动都会覆盖的临时文件肯定会被还原。正确做法要看你的环境分情况处理。如果你的系统是纯桌面版或服务器版默认带 systemd-resolved编辑/etc/systemd/resolved.conf[Resolve] DNS114.114.114.114 223.5.5.5 FallbackDNS119.29.29.29改完执行sudo systemctl restart systemd-resolved然后检查resolvectl status如果你的网络是由 NetworkManager 管理的桌面版常见更推荐用nmcli直接配置连接这样不会和 NetworkManager 打架nmcli connection modify Wired Connection ipv4.dns 114.114.114.114 223.5.5.5 nmcli connection up Wired Connection如果你是 Ubuntu Server 并且用 netplan 配置网络则编辑/etc/netplan/xx.yaml文件名因版本而异在对应网卡下加nameservers: addresses: - 114.114.114.114 - 223.5.5.5然后执行sudo netplan apply这个问题的根源是你知道要改 DNS但没搞清楚 DNS 由谁在管。Ubuntu 里现在是 systemd-resolved、NetworkManager、netplan 各管一摊你用命令ss -ulpn | grep :53可以看到127.0.0.53:53这个监听地址那是 systemd-resolved 的 stub 服务。理解了谁在听 53 端口就不会再去乱改/etc/resolv.conf了。3.3 解析结果不对时的三个对照实验解析结果不对是个很宽泛的说法可能是解析到旧 IP、解析超时、部分网络能解析部分不能。我通常做三个对照实验来缩小范围。第一个实验用本机默认 DNS 解析一次再用公共 DNS 解析一次看结果是否一致。nslookup www.example.com nslookup www.example.com 114.114.114.114如果默认 DNS 返回的结果和公共 DNS 不一致说明问题大概率出在你当前使用的 DNS 服务器缓存上或者运营商 DNS 有问题。这时可以临时把本机 DNS 切成公共 DNS 再访问验证一下。第二个实验查记录类型。比如你做邮件排障光查 A 记录没用要看 MXnslookup -typemx example.com如果 MX 指向的域名还有别名链就继续追 CNAME。很多人发信被退就是 MX 记录后面隐藏着一串 CNAME目标服务器不支持这样跳转。第三个实验绕过 DNS 直接测 IP。拿到解析出来的 IP 后直接用 IP 访问服务或者改 hosts 指向那个 IP。如果 IP 能通但域名不通说明解析链路有问题如果 IP 也不通说明是业务本身的问题和 DNS 无关。这套对照法很管用能迅速把DNS问题和非DNS问题分开。很多同事一上来就抓 DNS最后发现是服务器负载过高白白浪费了时间。另外如果你看到 Windows 事件日志里出现DNS Client events 错误 1012通常是 DNS 客户端服务在尝试解析时遇到了异常方向上是服务状态或者网络配置变动导致的。可以先services.msc里确认 DNS Client 服务是否正常运行再用ipconfig /flushdns清一下缓存最后检查网络适配器有没有被禁用或改动。多数情况下重启网络适配器就能恢复。4. 把DNS握在自己手里本机配置、内网自建与日常工具箱对大多数普通用户来说DNS 是别人给的自己只是被动消费。但对开发、运维、以及喜欢折腾的人来说DNS 是可以主动控制的资源。这一章讲三种主动控制的方式从轻到重排列。4.1 修改本机DNS的三种路径与公共DNS的选择思路本机修改 DNS 最常见三种路径系统网络配置、路由器配置、以及命令行。Windows 系统配置在网络和共享中心 → 更改适配器设置 → 属性 → Internet 协议版本 4 → 属性里把自动获取 DNS 服务器地址改成使用下面的 DNS 服务器地址。Linux 桌面版用 NetworkManager 的话可以在图形界面设置也可以直接用nmcli命令前面已经写过。命令行操作的好处是方便自动化尤其在批量配置服务器时。路由器配置则是把局域网所有设备的 DNS 统一在路由器上指定。这样全家设备都使用同一个 DNS省得每台单独改。前提是路由器本身允许自定义 DNS。公共 DNS 选择上我的建议是结合自己的网络环境。国内常用114.114.114.114中国网安和阿里 DNS223.5.5.5这两家在城内网络质量通常不错。国际上还有 Cloudflare 的1.1.1.1它在某些场景下可以作为交叉验证的对比解析器。不同 DNS 的解析结果理论上应该一致但受缓存和网络环境影响实际表现会有差异。做排障时我习惯把当前 DNS 和备用 DNS 都试一遍能快速判断是不是某个 DNS 缓存了脏数据。4.2 用dnsmasq在内网搭建一个说了算的DNS服务器内网开发环境里经常需要一堆自定义域名。比如你有一台 GitLab、一台测试环境、一台监控面板如果每台机器都改 hosts后续加机器加域名会非常痛苦。更好的做法是在内网搭一个 DNS 服务器统一管理这些域名。dnsmasq是我最常用的工具轻量、配置简单、资源占用低非常适合这种场景。安装apt update apt install -y dnsmasq配置写在/etc/dnsmasq.conf或单独的/etc/dnsmasq.d/custom.conf# 监听内网网卡地址表示只服务内网 listen-address192.168.1.1 # 启用缓存 cache-size1000 # 上游 DNS 配置内网没有的域名转发过去查询 server114.114.114.114 server223.5.5.5 # 直接把指定域名解析到内网地址 address/gitlab.dev/192.168.1.10 address/test.project.com/192.168.1.50配置里的address很强大所有匹配后缀的域名都会直接解析到你指定的 IP不需要额外建解析记录。改完重启systemctl restart dnsmasq然后把内网各设备的 DNS 指向192.168.1.1或者在路由器上把这个地址作为下发的 DNS。这套方案在开发环境价值很高。比如前端联调时接口域名指向测试服务器本地代码不需要改任何 URL。你再也不用去改每台机器的 hosts 文件也不用担心漏改。注意防火墙要放行 UDP/TCP 53 端口否则解析请求进不来。我用 dnsmasq 之后一个 20 台机器的开发小组彻底告别了为什么我这台解析不到的问题。需要说明的是dnsmasq 做的是轻量内网解析。如果你要托管一个互联网域名的权威解析或者需要复杂的策略控制按客户端返回不同结果那是 BIND9 或者 PowerDNS 的领域。内网自用dnsmasq 的性价比已经很高了。4.3 nslookup与dig排障时真正值得背的几条命令最后聊聊工具。排障 DNS 最常用的两个命令是nslookup和dig。Windows 自带nslookupLinux 通常需要安装dnsutils或bind9-dnsutils。nslookup适合快速查证基本用法# 查询 A 记录 nslookup example.com # 指定 DNS 服务器查询 nslookup example.com 114.114.114.114 # 查询 MX 记录 nslookup -typemx example.com # 查询 TXT 记录 nslookup -typetxt example.comdig的信息输出更详细适合深入分析# 查询 A 记录 dig example.com # 指定 DNS 服务器 dig 114.114.114.114 example.com # 只看结果忽略其他信息 dig example.com short # 查询 MX dig example.com MX排障时我习惯按顺序执行先dig example.com short拿到 IP再dig 223.5.5.5 example.com short对比公共 DNS 的结果。如果两个结果不一致基本可以断定是缓存不一致优先清理本机和当前 DNS 的缓存。dig还有一个有用参数是查询追踪它会把递归过程一步步打出来能清楚看到每个层级服务器返回的结果。内网自建 DNS 之后用这个参数验证自己配置的域名有没有走对链路效果很直观。最后说一个这些年反复踩到的坑如果你问我在 IP、DNS、域名这个三角关系里最容易忽略的是什么我会说排查时先确认当前 IP 是不是这台设备真正在用的 IP。我见过太多人排查 DNS 问题查了一下午最后发现目标服务器的 IP 早就换了。域名、hosts、DNS 配置本身没问题但 IP 指向的已经不是你以为的那台机器。所以我的排查顺序永远是先 IP再域名最后培训 DNS。先ping直连 IP确认目标在线再确认域名解析结果和预期一致最后才去分析缓存、TTL、DNS 服务状态这些细枝末节。顺序错了很容易在错误的方向上浪费时间。另一个建议是修改任何和域名解析相关的配置都要有记录、有回滚方案。hosts 文件多了脏条目、DNS 配置文件写错格式、dnsmasq 和 NetworkManager 相互覆盖这些我都遇到过。改之前备份一下改之后用命令验证能省去很多不必要的加班。IP、DNS、域名说到底就是谁在哪、叫什么、怎么找到的问题把根上的关系理顺剩下的排障都是在这个框架里做定位。