解决 Debian 12 VPS 上 DNS 自动重置的问题:一次完整的排查记录

解决 Debian 12 VPS 上 DNS 自动重置的问题:一次完整的排查记录

折腾了一晚上,终于把这个烦人的 DNS 问题给解决了。写篇博客记录一下,希望能帮到遇到同样问题的朋友。

问题描述

最近在 PureVoltage 买了一台 Debian 12 的 VPS,用来跑一些服务。但是遇到了一个很奇怪的问题:网络时不时就断开

经过排查,发现问题出在 DNS 上。每次我手动把 DNS 改成 Google DNS(8.8.8.8),网络就恢复正常。但过一段时间,DNS 又会自动变回服务商提供的 DNS(103.xxx.xxx.xxx),然后网络又挂了。

这种「改了又变回去」的情况实在太烦人了,必须找到根本原因。

第一步:确定网络管理方式

Debian 12 有好几种网络管理方式,不同的方式解决方案也不同。我们需要先搞清楚系统用的是哪种:

# 检查 systemd-networkd
systemctl status systemd-networkd

# 检查 NetworkManager
systemctl status NetworkManager

# 检查传统 networking 服务
systemctl status networking

# 检查 systemd-resolved
systemctl status systemd-resolved

# 查看 resolv.conf 是怎么管理的
ls -l /etc/resolv.conf

在我的 VPS 上,结果显示:

  • systemd-networkdactive (running)
  • NetworkManager — not found
  • networking — not found
  • systemd-resolvedactive (running)
  • /etc/resolv.conf — 是一个指向 /run/systemd/resolve/resolv.conf 的软链接

这说明系统使用的是 systemd-networkd + systemd-resolved 的组合。

第二步:找到 DNS 配置的来源

知道了网络管理方式后,下一步是找到 DNS 配置具体是从哪里来的:

# 检查运行时网络配置
ls -la /run/systemd/network/

# 检查 netplan 配置
cat /etc/netplan/*.yaml

# 检查 cloud-init 配置
cat /etc/cloud/cloud.cfg.d/*.cfg

# 查看当前 DNS 状态
resolvectl status

关键发现来了!在 /run/systemd/network/ 目录下有个 10-netplan-eth0.network 文件,而 netplan 的配置是由 cloud-init 自动生成的。

查看 netplan 配置文件,发现了问题所在:

network:
    version: 2
    ethernets:
        eth0:
            addresses:
            - 203.0.113.100/26
            - 2001:db8::100/64
            gateway4: 203.0.113.1
            gateway6: 2001:db8::1
            match:
                macaddress: aa:bb:cc:dd:ee:ff
            nameservers:
                addresses:
                - 1.1.1.1
                - 103.247.36.36    # <- 服务商的 DNS
                - 103.247.37.37    # <- 服务商的 DNS

原来是 cloud-init 在每次启动时都会重新生成网络配置,把 DNS 重置为服务商默认的设置。

第三步:永久解决问题

找到根本原因后,解决方案就很清晰了:

3.1 禁用 cloud-init 的网络管理

sudo tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg << 'EOF'
network: {config: disabled}
EOF

这会告诉 cloud-init「别管网络配置了,我自己来」。

3.2 删除 cloud-init 生成的旧配置

sudo rm /etc/netplan/50-cloud-init.yaml

3.3 创建自定义的 netplan 配置

sudo tee /etc/netplan/99-custom.yaml << 'EOF'
network:
    version: 2
    ethernets:
        eth0:
            addresses:
            - 203.0.113.100/26
            - 2001:db8::100/64
            routes:
            - to: default
              via: 203.0.113.1
            - to: default
              via: 2001:db8::1
            match:
                macaddress: aa:bb:cc:dd:ee:ff
            nameservers:
                addresses:
                - 8.8.8.8
                - 8.8.4.4
            set-name: eth0
EOF

注意几个变化:

  • 把 DNS 改成了 Google DNS
  • 使用 routes 替代了已废弃的 gateway4gateway6

3.4 设置正确的文件权限并应用配置

sudo chmod 600 /etc/netplan/99-custom.yaml
sudo netplan generate
sudo netplan apply

3.5 验证结果

resolvectl status eth0

输出:

Link 2 (eth0)
Current Scopes: DNS LLMNR/IPv4 LLMNR/IPv6
     Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
   DNS Servers: 8.8.8.8 8.8.4.4

完美!现在只有 Google DNS 了,不会再自动变回去。

踩过的坑

在解决这个问题的过程中,我踩了几个坑,分享出来给大家避雷:

坑一:直接改 /etc/resolv.conf

这个文件是由 systemd-resolved 动态管理的(注意它是个软链接),直接改没用,很快就会被覆盖。

坑二:只创建新配置不删除旧配置

如果不删除 50-cloud-init.yaml,两个配置文件会同时生效,DNS 服务器会被合并而不是替换。我一开始就犯了这个错误,结果 DNS 列表变成了一长串。

坑三:忘记禁用 cloud-init

如果不禁用 cloud-init 的网络管理,下次重启它又会重新生成配置文件,之前的修改全白费。

总结

这次问题的根本原因是 cloud-init 持续管理网络配置,导致我们的手动修改总是被覆盖。

解决思路:

  1. 先诊断系统使用的网络管理方式
  2. 找到配置的实际来源
  3. 从源头解决问题,而不是在下游修修补补

这个思路其实适用于很多 Linux 问题的排查。与其反复改一个被别的服务管理的文件,不如找到那个「管理者」,要么让它按你的意思来,要么直接让它别管。

希望这篇文章对你有帮助!如果你也遇到了类似的问题,欢迎在评论区交流。


写于深夜,解决问题后的愉悦心情无以言表。去睡觉了,晚安! :crescent_moon: