Why systemd-networkd for Homelab Networking
If you’ve installed Debian 13 “Trixie” or Ubuntu 24.04 recently, your system already ships with systemd-networkd installed and ready. It’s the default network manager on Arch Linux too. Despite this, many homelab guides still default to NetworkManager, netplan, or the legacy /etc/network/interfaces — and then hit a wall the moment they need a Linux bridge for KVM, a VLAN interface for network segmentation, or a bond for link aggregation.
systemd-networkd handles all of these natively with three configuration file types:
.link— matches hardware devices by MAC, driver, or path and sets link-level parameters (MTU, MAC address, wake-on-lan).netdev— defines virtual network devices (bridges, bonds, VLANs, VRFs, VXLANs).network— applies IP addressing, routing, DNS, DHCP, and bridge port membership to any matched link
The configuration lives in /etc/systemd/network/ and follows simple lexicographic ordering rules. No daemon restart required — networkctl reconfigure applies changes on the fly.
For a homelab hypervisor running Proxmox, KVM, or Docker on a Debian 13 host, switching to systemd-networkd means you get predictable, boot-order-independent networking with zero GUI dependencies.
Checking Your Current Network State
Before changing anything, survey what you’re running today:
|
|
If systemd-networkd isn’t active, you’re likely running NetworkManager (common on Ubuntu Server desktop-flavored installs) or netplan (Ubuntu default up to 24.04). Both can coexist with systemd-networkd on different interfaces, but for simplicity, pick one — systemd-networkd — for all host-level networking.
Preparing the Host: Disabling Conflicting Managers
You don’t need to uninstall anything. Just stop and disable the services you aren’t using:
|
|
If you’re on Ubuntu, also unlink the default /etc/resolv.conf so systemd-resolved manages DNS:
|
|
Linux Bridge Configuration for KVM and Docker
The most common homelab networking scenario: you have a single physical NIC and need a Linux bridge so VMs and containers can share the host’s connection to your LAN.
Bridge Virtual Device — br0.netdev
Create /etc/systemd/network/10-br0.netdev:
|
|
Setting a static MAC on the bridge is optional but recommended — it prevents the MAC from changing on reboot, which would break DHCP reservations and firewall rules.
Bridge Port Membership — 20-br0-enp2s0.network
Create /etc/systemd/network/20-br0-enp2s0.network:
|
|
That’s it. The physical interface enp2s0 becomes a bridge port. No IP address on the physical NIC — all addressing happens on the bridge.
Bridge IP Configuration — 30-br0.network
Create /etc/systemd/network/30-br0.network:
|
|
For a static IP instead:
|
|
Apply the configuration:
|
|
Verify bridge state:
|
|
KVM guests can now attach their virtual NICs directly to br0 via bridged networking, and Docker can be configured to use br0 through macvlan or ipvlan.
VLAN Interface Configuration for Network Segmentation
If your upstream switch delivers tagged VLANs, you need VLAN interfaces on the host. The standard pattern: attach the VLAN to the bridge so all VMs on the bridge can reach their respective VLAN — or attach VLANs directly to the physical NIC for host-only segmentation.
VLAN on Physical NIC — VLAN 10 Management
Create /etc/systemd/network/10-vlan10.netdev:
|
|
Then /etc/systemd/network/30-vlan10.network:
|
|
Attach the VLAN to the physical uplink by adding the parent reference in a .network file:
Create /etc/systemd/network/20-enp2s0-vlan10.network:
|
|
Repeat for VLAN 20 (services) and VLAN 30 (IoT):
|
|
And similarly for vlan30 with Id=30.
VLAN Trunk on a Bridge (for VM access to multiple VLANs)
For KVM guests that need access to multiple VLANs, attach the VLAN interfaces to the bridge:
Create /etc/systemd/network/10-br0.netdev (add to existing):
|
|
No VLAN reference in the bridge .netdev. Instead, modify 20-enp2s0.network to list VLANs on the bridge port:
|
|
And create .network files for each VLAN that set the bridge as their parent:
|
|
This way, the host bridge br0 carries untagged traffic, while VLANs 10, 20, and 30 are trunked through the bridge. VMs attached to br0 can be configured with VLAN filtering in libvirt.
Apply everything:
|
|
Verify VLAN tagging:
|
|
Output should show the PVID on the bridge port and the tagged VLANs:
port vlan-id
enp2s0 1 PVID Egress Untagged
10
20
30
br0 1 PVID Egress Untagged
Bond (Link Aggregation) Configuration
For servers with dual NICs, a bond provides redundancy and increased throughput. systemd-networkd supports all standard bonding modes — for homelab use, 802.3ad (LACP) is the standard choice when your switch supports it.
Bond Virtual Device — bond0.netdev
Create /etc/systemd/network/10-bond0.netdev:
|
|
Bond Slave Interfaces
Create /etc/systemd/network/20-enp2s0-bond.network:
|
|
Create /etc/systemd/network/21-enp3s0-bond.network:
|
|
Bond IP Configuration
Create /etc/systemd/network/30-bond0.network:
|
|
Or static:
|
|
Apply:
|
|
Verify bonding:
|
|
Look for MII Status: up on each slave and Bonding Mode: IEEE 802.3ad Dynamic link aggregation.
Combining Bond and Bridge
Need both bonding and bridging? Layer them — bond first, bridge on top:
10-bond0.netdev as above, then 10-br0.netdev with Kind=bridge, and:
|
|
This gives you a bonded, bridged setup where VMs, LXC containers, and Docker can all share redundant uplinks.
Applying Changes and Rolling Back
systemd-networkd applies configuration files in lexicographic order. The standard naming convention is XX-name.type where XX is a two-digit priority — lower numbers apply first.
Apply a single interface:
|
|
Reload all configuration:
|
|
Roll back a change: simply rename or remove the .network or .netdev file and reconfigure:
|
|
Common gotcha: if you reconfigure the interface carrying your SSH session, you get locked out. Always test changes through an out-of-band management interface (IPMI, iDRAC, serial console), or use at now + 1 minute to schedule a rollback before applying breaking config changes:
|
|
Conclusion
systemd-networkd is the most straightforward way to manage Linux networking in a homelab. Its declarative .network and .netdev files make bridge, VLAN, and bond configuration predictable and repeatable — no daemon GUI, no Python-generated config files, just clean INI-style files that work on every modern distro.
For a Debian 13 hypervisor running KVM, LXC, and Docker, the combination of a Linux bridge with tagged VLAN interfaces and optional LACP bonding covers every networking scenario you’ll encounter. And because systemd-networkd is built into systemd itself, there’s no additional package to install or maintain.
Next time you provision a new homelab host, skip NetworkManager and write a .network file instead. Your future self — the one adding a second NIC or creating a VLAN trunk — will thank you.