Debian系统里,systemd-networkd和NetworkManager并存的情况其实非常普遍,尤其是在从最小化安装升级到桌面环境,或者手动安装了某些依赖包之后。你不需要去纠结它们为什么在一起,需要解决的是“现在怎么让网络正常工作”这个问题。这两个服务同时管理网络接口,最直接的后果就是IP地址冲突、DNS配置被覆盖、路由表混乱,甚至某个接口直接断连。处理这个问题的核心思路只有一条:同一时间,让同一个网络接口只被一个服务管理。

先判断当前是谁在控制网络

动手改配置之前,先搞清楚系统现状。运行以下命令查看两个服务的状态:

systemctl status systemd-networkd
systemctl status NetworkManager

如果两个都是 active (running) 状态,那冲突几乎不可避免。接着用 networkctl 和 nmcli 分别查看它们各自管理了哪些接口:

networkctl list
nmcli device status

networkctl 输出中,如果某个接口的 SETUP 列显示为 "unmanaged",说明 systemd-networkd 没有接管它。nmcli 输出中,如果某个设备的 STATE 显示为 "unmanaged",说明 NetworkManager 放过了它。如果同一个接口在两边都显示为 "configured" 或 "connected",这就是冲突点。另外,检查 /etc/network/interfaces 文件,ifupdown 这套传统配置方式如果还在用,会让情况更复杂,因为 NetworkManager 默认会忽略在该文件中有配置的接口,但 systemd-networkd 不会。

方案一:完全使用 systemd-networkd,移除 NetworkManager

这个方案适合服务器、虚拟化主机、容器宿主机等不需要频繁切换无线网络和VPN的场景。systemd-networkd 配置简单、依赖少、启动快,是 systemd 生态的原生组件。

首先停止并禁用 NetworkManager:

systemctl stop NetworkManager
systemctl disable NetworkManager
systemctl mask NetworkManager

mask 命令会彻底防止它被其他服务间接启动。接着确保 systemd-networkd 和 systemd-resolved(用于DNS处理)启用:

systemctl enable systemd-networkd
systemctl enable systemd-resolved
systemctl start systemd-networkd
systemctl start systemd-resolved

然后处理 DNS 符号链接,让 /etc/resolv.conf 指向 systemd-resolved 生成的文件:

ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

接下来配置网络接口。systemd-networkd 的配置文件放在 /etc/systemd/network/ 目录下。有线接口通常命名为 .network 文件,比如 /etc/systemd/network/20-wired.network:

[Match]
Name=enp3s0

[Network]
DHCP=yes

如果需要静态IP,则这样写:

[Match]
Name=enp3s0

[Network]
Address=192.168.1.100/24
Gateway=192.168.1.1
DNS=192.168.1.1

无线网络也可以用 systemd-networkd 管理,但需要配合 wpa_supplicant。先创建 /etc/wpa_supplicant/wpa_supplicant-wlp2s0.conf:

network={
    ssid="你的WiFi名称"
    psk="你的WiFi密码"
}

然后启用 wpa_supplicant 对应接口的服务:

systemctl enable wpa_supplicant@wlp2s0
systemctl start wpa_supplicant@wlp2s0

再创建 /etc/systemd/network/30-wireless.network:

[Match]
Name=wlp2s0

[Network]
DHCP=yes

重启 systemd-networkd 即可。这种方案的缺点很明显:没有图形化的网络管理工具,切换WiFi需要手动改配置文件或使用 wpa_cli,对于笔记本用户不太友好。但它的优势在于稳定、资源占用极低,配置文件可以版本化管理,非常适合基础设施环境。

方案二:完全使用 NetworkManager,让 systemd-networkd 退让

桌面用户、笔记本用户、需要频繁切换网络环境的场景,应该毫不犹豫地选择 NetworkManager。它提供了完善的图形界面、命令行工具 nmcli 和文本界面 nmtui,对无线网络、移动宽带、PPPoE、VPN 插件的支持都非常成熟。

首先要做的是让 systemd-networkd 不再管理任何接口。最干净的做法不是停止服务,而是清空它的配置目录并确保没有 .network 文件匹配到接口:

rm -f /etc/systemd/network/*.network
rm -f /etc/systemd/network/*.netdev

然后重启 systemd-networkd,此时 networkctl list 应该显示所有接口状态为 "unmanaged"。如果还担心它干扰,可以直接禁用:

systemctl stop systemd-networkd
systemctl disable systemd-networkd
systemctl mask systemd-networkd

但这里有一个重要的细节:很多 Debian 衍生系统会默认安装 ifupdown,并且 /etc/network/interfaces 里可能有 lo 接口的配置。NetworkManager 的默认行为是忽略在 interfaces 文件中明确配置的接口。为了让 NetworkManager 接管所有物理网卡,需要编辑 /etc/NetworkManager/NetworkManager.conf,确保 [ifupdown] 段中的 managed 值设为 true:

[ifupdown]
managed=true

同时,检查 /etc/network/interfaces 文件,只保留 loopback 接口的配置,其他物理接口的配置全部注释或删除:

auto lo
iface lo inet loopback

然后重启 NetworkManager:

systemctl restart NetworkManager

现在用 nmcli device status 检查,物理网卡应该显示为 "managed" 状态。对于 DNS 处理,NetworkManager 也会接管 /etc/resolv.conf。如果你之前已经切换到 systemd-resolved,需要决定是让 NetworkManager 直接写 resolv.conf,还是继续用 systemd-resolved 作为后端。推荐后者,因为 resolved 提供了更强大的 DNS 缓存和分域名解析能力。在 NetworkManager.conf 的 [main] 段添加:

[main]
dns=systemd-resolved

然后重启 NetworkManager,它会通过 D-Bus 与 systemd-resolved 通信,不再直接写 /etc/resolv.conf。此时 /etc/resolv.conf 应该保持指向 resolved 的 stub 文件。

方案三:精细化共存,按接口分配管理权

某些特殊场景下,你可能确实需要两个服务同时运行。比如服务器的主要有线网卡由 systemd-networkd 管理以保证稳定性,而偶尔插入的 USB 4G 网卡或无线网卡希望用 NetworkManager 来处理,因为它的移动宽带支持和自动配置能力更强。这种混合模式可以实现,但必须严格划清界限。

核心机制是让 systemd-networkd 只处理你指定的接口,NetworkManager 处理剩下的。systemd-networkd 的 .network 文件通过 [Match] 段精确匹配接口名称,没有匹配到的接口它不会去碰。NetworkManager 则通过设备状态和 udev 规则来控制。

假设有线网卡 enp3s0 和 enp4s0 交给 systemd-networkd,在 /etc/systemd/network/ 下为它们创建对应的 .network 文件。然后让 NetworkManager 忽略这些接口。创建 /etc/NetworkManager/conf.d/unmanaged.conf:

[keyfile]
unmanaged-devices=interface-name:enp3s0;interface-name:enp4s0

重启 NetworkManager 后,这两个接口在 nmcli 中会显示为 "unmanaged"。其他接口如 wlp2s0 或 usb0 则由 NetworkManager 自动接管。这种方案的难点在于维护 discipline,新增网卡时必须明确决定归属,否则容易出现遗漏。另外,systemd-resolved 和 NetworkManager 的内置 DNS 处理仍然可能冲突,建议全局统一使用 systemd-resolved,NetworkManager 通过 dns=systemd-resolved 配置项将 DNS 请求转发给它。

DNS 冲突的彻底解决

不管选哪种方案,DNS 配置混乱是共存状态下最常出现的问题。表现形式为:域名解析时快时慢、某些域名无法解析、/etc/resolv.conf 文件被反复覆盖。根本原因是有多个服务在争抢 /etc/resolv.conf 的写入权。

Debian 系统中,常见的 DNS 处理方有 resolvconf、systemd-resolved、NetworkManager 内置 DNS 和直接静态文件。要彻底解决,必须只保留一个。推荐使用 systemd-resolved 作为唯一的 DNS 解析后端,因为它提供了统一接口、缓存、DNSSEC 验证和分域名解析。具体做法:

apt purge resolvconf
systemctl enable systemd-resolved
systemctl start systemd-resolved
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

然后在 NetworkManager.conf 中设置 dns=systemd-resolved,在 systemd-networkd 的 .network 文件中,DNS 地址也可以配,但最终都会通过 resolved 的 D-Bus API 统一处理。这样无论哪个服务触发了 DNS 配置变更,最终都汇聚到 systemd-resolved 这一个进程中,冲突自然消失。

常见故障排查手法

网络不通时,不要盲目重启服务。按顺序检查:

1. 接口链路状态:ip link show,看 state 是否为 UP。

2. IP 地址获取:ip addr show dev <接口名>,确认是否有 IPv4/IPv6 地址。

3. 路由表:ip route show,默认路由是否存在,网关是否正确。

4. DNS 解析:resolvectl status 或 systemd-resolve --status,查看每个接口的 DNS 服务器和搜索域。

5. 服务日志:journalctl -u systemd-networkd -f 或 journalctl -u NetworkManager -f,日志会明确告诉你哪个服务对接口做了什么操作,以及失败原因。

6. 如果怀疑是多个服务争抢导致,临时停掉其中一个服务,观察网络是否恢复,这能快速定位责任方。

最终选择建议

没有绝对正确的方案,只有适合场景的方案。服务器和云实例,直接用 systemd-networkd,去掉一切图形化网络工具,配置文件纳入 Ansible 或 cloud-init 管理。桌面和笔记本,用 NetworkManager,把 systemd-networkd 的配置清空并禁用服务,让 NetworkManager 全权接管。特殊混合场景,按接口严格分配管理权,并统一 DNS 后端。理解了这两个服务的本质区别——systemd-networkd 是轻量级的、基于配置文件的网络管理守护进程,NetworkManager 是功能丰富的、事件驱动的网络配置套件——你就能根据实际需求做出判断,而不是在网上搜到一条命令就盲目执行。