前言
最近在玩一个小鸡的时候,发现一个奇特的现象:VPS 上的 DNS 改了好几次,过两天再看,又不知道被什么给"偷偷"改回去了。
现象是这样的:明明在 /etc/resolv.conf 里把 DNS 改成了 8.8.8.8,域名解析一直很正常。但某天开始 VPS 突然无法解析域名,软件也更新不了,进系统一看——resolv.conf 里的内容被换回了默认值,我改的东西没了。改了三次后才反应过来,不是我改的方式有问题,应该是这个文件本身会被系统自动重写。
今天就把这个现象的来龙去脉讲清楚,为什么会被覆盖以及怎么改才不会失效,最后再给大家推荐一些好用的公共 DNS 。
为什么 resolv.conf 会被自动覆盖
我之前以为 /etc/resolv.conf 就是个普通配置文件,改了就生效,永久保存。实际上它更像一个"展示窗口":在大多数系统上,这个文件是由网络管理服务自动生成和维护的。
两个常见的"幕后黑手":
DHCP 客户端:VPS 拿到 IP 的同时,也会从 DHCP 拿到机房默认的 DNS 地址,网络服务重启或者续租时,就会按拿到的值重写
resolv.conf;系统网络管理服务(如 systemd-resolved、NetworkManager):系统更新、网络服务重启后,同样可能按自己的配置重新生成这个文件。
所以问题不是我改错了,而是改完之后,服务一重启、系统一更新,文件又被按它的逻辑重新生成了一遍,这就是为什么"改了三次都失效"。
顺便一提,这个坑的隐蔽性在于它不立刻发作:改完 DNS 当下一切正常,直到某次重启网络、更新系统包之后,解析突然挂了,你很难第一时间联想到是"几天前改的 DNS 被覆盖了"。
改对地方,再上锁
分两步,先让内容变对,再让它变不了。
第一步:改 DNS 的正确姿势
直接编辑 /etc/resolv.conf:
nameserver 8.8.8.8
nameserver 1.1.1.1 如果系统里跑着 systemd-resolved,更稳妥的做法是改它的配置文件 /etc/systemd/resolved.conf:
[Resolve]
DNS=8.8.8.8 1.1.1.1 改完执行 systemctl restart systemd-resolved 让配置生效。从源头改,比只改 resolv.conf 更抗重写。
第二步:chattr 上锁
内容改对之后,给文件上一把"防写锁":
chattr +i /etc/resolv.conf +i 属性会把文件设为不可修改——即使是 root,不经解锁也不能改写。这样无论是 DHCP 续租还是系统更新,都没法再动这个文件,你的 DNS 配置从此钉死。
两件配套的事别忘:
想改回来时,先解锁:
chattr -i /etc/resolv.conf,改完再锁上。别到时候自己也被锁外面;验证锁是否生效:再执行
chattr +i前后分别尝试编辑文件,或者用lsattr /etc/resolv.conf查看属性,有 i 标记就是锁上了。
公共 DNS 怎么选
锁之前先确认你锁的内容是对的。推荐几个常见好用的公共 DNS:
8.8.8.8 / 8.8.4.4(Google):解析质量稳定,海外域名表现好;
1.1.1.1(Cloudflare):响应速度快,主打隐私;
9.9.9.9(Quad9):自带恶意域名拦截,安全性取向。
DNS 选择建议:VPS 在海外、访问海外服务为主,8.8.8.8 和 1.1.1.1 都是好选择,也可以两条都写做互备。如果你的应用对解析速度敏感,可以逐个 ping 或者用 dig 对比响应时间,以自己 VPS 的实测为准,别人说的快慢在你机器上未必成立。
总结
DNS 被覆盖是因为 resolv.conf 是被系统服务自动维护的文件,手改必被重写。解法就两步:先从源头(systemd-resolved 配置)把 DNS 改对,再用 chattr +i 给文件上锁,一劳永逸。
改系统文件前记得留后路:解锁命令 chattr -i 也一起记下来,别把自己锁在门外。
下一篇预告:排查 DNS 时我还遇到另一个问题——装了宝塔面板的机器,面板会自动生成一套 iptables 规则,和原有防火墙规则撞车,然后端口被拦得莫名其妙的。到时候展开讲讲怎么核对规则来源、然后把冲突理清楚。
