On modern Linux distributions, two network stacks compete for the same job: systemd-networkd and NetworkManager. Both are mature, both are supported by Red Hat, SUSE, Canonical and Debian — and yet neither stack fits every use case. Anyone who picks the wrong one on a Proxmox host, a TrueNAS uplink or an OPNsense backend will later be chasing MAC address changes, lost VLAN tags or DHCP race conditions.
This article positions both stacks in a server context, shows bridge and VLAN configurations in each and describes how to migrate cleanly from one to the other.
The two philosophies at a glance
The difference is not purely technical — it is conceptual. systemd-networkd was introduced in 2014 as a minimalist, declarative complement to systemd. Configuration lives in static .network, .netdev and .link files under /etc/systemd/network/. The daemon is small, has few dependencies and knows no plugins.
NetworkManager originally came from the Fedora world (2004) and was designed for desktop users switching between WiFi, Ethernet, modems and VPNs. It brings a D-Bus service, nmcli, nmtui, a GNOME applet integration and an extensive plugin system for OpenVPN, WireGuard, Cisco AnyConnect and more.
| Criterion | systemd-networkd | NetworkManager |
|---|---|---|
| Config format | Declarative (.network/.netdev) | Keyfile or D-Bus/nmcli |
| Memory footprint | Very small (~5 MB RSS) | Larger (~30-60 MB RSS) |
| VPN plugins | No (external tools) | Yes (OpenVPN, WireGuard, IPsec) |
| WiFi roaming | Via wpa_supplicant/iwd | Natively integrated |
| Runtime changes | Restart the unit | Live via D-Bus/nmcli |
| Container/cloud images | Default in many minimal images | Rarely preinstalled |
| Reproducibility (IaC) | Excellent (text files in Git) | Possible, but more effort |
For servers, the rule of thumb is: the closer a system sits to “pure infrastructure”, the better networkd fits. The closer it sits to “changing user sessions”, the more NetworkManager makes sense.
When systemd-networkd is the right choice
For most server roles we build for customers, systemd-networkd is the pragmatic default:
- Hypervisors (Proxmox, KVM on Debian, Nutanix CE) with static bridges, bonds and VLANs
- Container hosts (Docker, Podman, LXC) without complex roaming requirements
- Storage servers such as TrueNAS uplink nodes, NFS gateways or backup targets
- Bare-metal cloud instances from minimal images (Ubuntu Server, Debian Cloud, Fedora CoreOS)
- Embedded/edge systems on ARM hardware, where every MB of RAM counts
The big plus: all configuration files are small, version-controllable text files. An Ansible playbook or a Git repo with /etc/systemd/network/*.network is enough to provision ten identical hypervisors identically.
A typical bridge setup for a Proxmox host with LACP bond and VLAN-aware bridge looks like this:
# /etc/systemd/network/10-bond0.netdev
[NetDev]
Name=bond0
Kind=bond
[Bond]
Mode=802.3ad
TransmitHashPolicy=layer3+4
MIIMonitorSec=1s
LACPTransmitRate=fast
# /etc/systemd/network/20-bond0-slaves.network
[Match]
Name=enp1s0f0 enp1s0f1
[Network]
Bond=bond0
# /etc/systemd/network/30-vmbr0.netdev
[NetDev]
Name=vmbr0
Kind=bridge
[Bridge]
VLANFiltering=yes
STP=no
# /etc/systemd/network/40-vmbr0.network
[Match]
Name=vmbr0
[Network]
Address=10.20.10.5/24
Gateway=10.20.10.1
DNS=10.20.10.1
VLAN=vmbr0.100
[BridgeVLAN]
VLAN=100-199
After systemctl restart systemd-networkd the configuration is live — and can be verified with networkctl status vmbr0.
When NetworkManager still makes sense
NetworkManager is not just “the thing for laptops”. In the following server scenarios it is even the better choice:
- RHEL/Rocky/Alma from 9 onwards: Red Hat never fully supported networkd in the RHEL context;
nmcliis the official interface — including Kickstart integration. - Roaming edge boxes with cellular modems (LTE/5G) and Ethernet failover.
- VPN gateways with user sessions: NetworkManager can store OpenVPN, WireGuard and IPsec profiles per user and activate them on login.
- Workstation-like servers: development and test machines with KVM, where a USB Ethernet is sometimes plugged in.
- Systems with frequent runtime changes: an
nmcli con mod eth0 ipv4.addresses 10.20.30.5/24 && nmcli con up eth0is easier at runtime than redefining a unit.
The same bridge setup as above, but in NetworkManager:
nmcli con add type bond ifname bond0 con-name bond0 \
bond.options "mode=802.3ad,lacp_rate=fast,xmit_hash_policy=layer3+4,miimon=100"
nmcli con add type ethernet ifname enp1s0f0 master bond0 con-name bond0-slave1
nmcli con add type ethernet ifname enp1s0f1 master bond0 con-name bond0-slave2
nmcli con add type bridge ifname vmbr0 con-name vmbr0 \
bridge.stp no bridge.vlan-filtering yes
nmcli con mod vmbr0 ipv4.addresses 10.20.10.5/24 ipv4.gateway 10.20.10.1 \
ipv4.dns 10.20.10.1 ipv4.method manual
nmcli con add type bridge-slave ifname bond0 master vmbr0 con-name bond0-in-vmbr0
nmcli con up bond0-slave1 && nmcli con up bond0-slave2
nmcli con up vmbr0
Both paths reach the same target — the difference lies in the mindset: networkd describes a target state, NetworkManager runs a series of commands that produce a target state.
In practice: VLAN tagging on a storage uplink
A common special case in our Linux projects is a VLAN-tagged uplink between hypervisor and storage. The pattern is the same everywhere: leave the physical NIC untouched, put a VLAN interface on top, configure the IP there.
systemd-networkd:
# /etc/systemd/network/10-storage.network
[Match]
Name=enp2s0
[Network]
VLAN=storage.42
# /etc/systemd/network/20-storage-vlan.netdev
[NetDev]
Name=storage.42
Kind=vlan
[VLAN]
Id=42
# /etc/systemd/network/21-storage-vlan.network
[Match]
Name=storage.42
[Network]
Address=10.42.0.5/24
NetworkManager:
nmcli con add type vlan con-name storage.42 ifname storage.42 \
dev enp2s0 id 42 \
ipv4.method manual ipv4.addresses 10.42.0.5/24
nmcli con up storage.42
In both cases we recommend enabling jumbo frames (MTU 9000) on the storage VLAN if the switch supports them end-to-end. In networkd via MTUBytes=9000, in NetworkManager via 802-3-ethernet.mtu 9000 or vlan.mtu 9000.
Migration in both directions
Switching between stacks is routine — for example when a Proxmox host is moved from ifupdown2 to networkd, or when a RHEL server is cleaned up to run only networkd.
The procedure is always the same:
- Inventory:
ip -o link,ip -o addr,ip -o -4 route,ip -o -6 routeandnmcli -t con showornetworkctl listas the starting point. - Write the target configuration and place it in
/etc/systemd/network/or as annmconnection. Review it as text before activating — typos in[Match]or MAC addresses are the number-one source of errors. - Prepare a fallback:
at now + 10 min <<< 'systemctl restart networking'or keep a serial console window open. - Disable the old service:
systemctl disable --now NetworkManagerorsystemctl disable --now systemd-networkd systemd-networkd-wait-online. - Start the new service and verify with
networkctl/nmcli con show --active. - Separate DNS:
/etc/resolv.confbelongs to eithersystemd-resolvedin both stacks or is statically overwritten. Dual management leads to shifting nameservers — a classic, hard-to-debug bug.
Important: NetworkManager knows an “unmanaged” mode. Interfaces managed by networkd should be explicitly excluded in /etc/NetworkManager/conf.d/10-unmanaged.conf so the two services do not fight over them.
Recommendation for typical roles
As a rough guideline from our project experience:
| Role | Recommendation |
|---|---|
| Proxmox VE host | systemd-networkd or ifupdown2 (Proxmox default) |
| Debian/Ubuntu container host | systemd-networkd |
| RHEL/Rocky server | NetworkManager (officially supported) |
| TrueNAS/SAN node (Debian-based) | systemd-networkd |
| OPNsense backend (FreeBSD) | Own stack — not relevant here |
| Edge box with LTE modem | NetworkManager |
| VDI/terminal server | NetworkManager (VPN, user sessions) |
| Kubernetes node | systemd-networkd, CNI takes over pod networking |
There is no “better” stack — only the right one. Pick one, roll it out consistently via configuration management, and you will save yourself more grief long term than any micro-optimisation could deliver.
DATAZONE supports you in designing and operating your Linux server networks — from migrating individual hosts to unifying entire clusters via Ansible. If you are unsure which network stack fits your environment in Proxmox, TrueNAS or OPNsense projects, get in touch. We will look at your requirements together and deliver a recommendation that will still hold up in three years.
More on these topics:
More articles
NetBox as a DCIM Starter Kit for SMBs
NetBox as DCIM and IPAM for SMBs: model sites, racks, devices and IP addresses cleanly, ready in four hours, integrated with Ansible and Prometheus.
Linux ZFS Boot Mirror Broken: 4 Rescue Approaches
A broken ZFS boot pool takes Proxmox and Ubuntu offline. Four field-tested paths back to a running system via live ISO, chroot and bootloader rebuild.
TrueNAS SMB Multichannel: Configuring 10GbE Properly
Step-by-step guide to enabling SMB Multichannel on TrueNAS Scale for 10GbE clients, with Windows client verification and common configuration pitfalls.