While Network Manager is the default networking stack on most desktop and server distributions, there are situations where systemd-networkd is the better choice for a KVM hypervisor. If you are running a headless server, want minimal overhead, or prefer declarative configuration files over a daemon-heavy approach, systemd-networkd delivers exactly that. This guide covers how to configure bridge networking on a KVM host using systemd-networkd on Ubuntu 24.04 Server and RHEL 10.

When to Use systemd-networkd Over Network Manager

Network Manager is built for flexibility – it handles Wi-Fi, VPNs, mobile broadband, and dynamic network changes gracefully. That flexibility comes with overhead that a dedicated KVM server does not need. Here is when systemd-networkd makes more sense:

  • Headless servers with static network configurations that rarely change
  • Minimal installations where you want fewer running services
  • Container hosts and hypervisors where predictable, fast boot-time networking matters
  • Environments where you want plain-text configuration files version-controlled in git
  • Systems already using systemd for everything else and you want consistency

The configuration uses .netdev files to define virtual devices (like bridges) and .network files to configure addressing and link membership. Both go in /etc/systemd/network/ and are processed in lexical order by filename.

Prerequisites

  • A KVM host running Ubuntu 24.04 Server or RHEL 10
  • Root or sudo access
  • Knowledge of your physical interface name (check with ip link show)
  • Console access recommended when changing network configuration remotely

Step 1 – Disable Network Manager (If Active)

On systems where Network Manager is running, you need to disable it before switching to systemd-networkd. Running both at the same time causes conflicts.

sudo systemctl stop NetworkManager
sudo systemctl disable NetworkManager
sudo systemctl mask NetworkManager

On Ubuntu 24.04 Server with Netplan, also stop the Netplan backend if present.

sudo systemctl stop systemd-networkd
sudo rm -f /etc/netplan/*.yaml

Verify Network Manager is no longer active.

systemctl status NetworkManager

Step 2 – Enable systemd-networkd and systemd-resolved

Enable both systemd-networkd for network configuration and systemd-resolved for DNS resolution.

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

Link the resolved stub to /etc/resolv.conf so applications use systemd-resolved for DNS.

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

Step 3 – Create the Bridge Device

Create a .netdev file that defines the bridge interface. The filename prefix (e.g., 10-) controls processing order – lower numbers are processed first.

sudo tee /etc/systemd/network/10-br0.netdev <<EOF
[NetDev]
Name=br0
Kind=bridge
EOF

This tells systemd-networkd to create a bridge device named br0 at boot time.

Step 4 – Bind the Physical Interface to the Bridge

Create a .network file for your physical Ethernet interface that assigns it as a member of the bridge. Replace enp3s0 with your actual interface name.

sudo tee /etc/systemd/network/20-enp3s0.network <<EOF
[Match]
Name=enp3s0

[Network]
Bridge=br0
EOF

This file matches the physical interface by name and adds it to the br0 bridge. Notice there is no IP configuration here – the physical interface should not have an IP address when it is a bridge member.

Step 5 – Configure the Bridge with a Static IP

Create the .network file for the bridge itself. This is where you assign the IP address, gateway, and DNS settings.

sudo tee /etc/systemd/network/30-br0.network <<EOF
[Match]
Name=br0

[Network]
Address=192.168.1.100/24
Gateway=192.168.1.1
DNS=8.8.8.8
DNS=8.8.4.4
Domains=example.com

[Link]
RequiredForOnline=carrier
EOF

The [Link] section with RequiredForOnline=carrier prevents systemd from waiting for a full online state before considering the network ready, which speeds up boot time.

Alternative – DHCP Configuration

If you prefer DHCP on the bridge (common in lab environments), replace the bridge network file with this.

sudo tee /etc/systemd/network/30-br0.network <<EOF
[Match]
Name=br0

[Network]
DHCP=ipv4

[DHCP]
UseDNS=true
UseDomains=true

[Link]
RequiredForOnline=carrier
EOF

Step 6 – Restart systemd-networkd

Apply the new configuration by restarting the service. If you are connected over SSH, you may lose your session briefly.

sudo systemctl restart systemd-networkd

If you want to apply changes without a full restart, use networkctl reload (available in systemd 249+).

sudo networkctl reload

Step 7 – Verify the Configuration

Run through a series of checks to confirm everything is working.

Check the overall network status.

networkctl status

Check the bridge specifically.

networkctl status br0

Expected output should show the bridge with your static IP, the linked physical interface, and an “online” or “routable” state.

Verify the IP address assignment.

ip addr show br0

Confirm the physical interface is a bridge member.

bridge link show

Test DNS resolution.

resolvectl status
ping -c 3 google.com

List all managed links and their states.

networkctl list

Step 8 – Use the Bridge with KVM Virtual Machines

With the bridge active, attach VMs to it during creation.

virt-install \
  --name myvm \
  --ram 2048 \
  --vcpus 2 \
  --disk size=20 \
  --os-variant ubuntu24.04 \
  --network bridge=br0 \
  --cdrom /var/lib/libvirt/images/ubuntu-24.04.iso

For existing VMs, edit the domain XML with virsh edit vmname and set the interface section to use the bridge.

<interface type='bridge'>
  <source bridge='br0'/>
  <model type='virtio'/>
</interface>

File Summary

Here is a recap of the three configuration files and their purpose.

FilePurpose
/etc/systemd/network/10-br0.netdevDefines the br0 bridge device
/etc/systemd/network/20-enp3s0.networkBinds the physical interface to the bridge
/etc/systemd/network/30-br0.networkAssigns IP, gateway, DNS to the bridge

Troubleshooting

If the bridge does not come up, check the journal for errors.

journalctl -u systemd-networkd -b --no-pager

Common issues include typos in interface names in the [Match] section, missing .netdev files, or leftover Network Manager configurations. Verify that no other service is managing the same interfaces.

systemctl list-units --type=service | grep -i network

Only systemd-networkd.service and systemd-resolved.service should be active for network management.

Summary

Using systemd-networkd for KVM host networking gives you a lightweight, file-based configuration that is easy to understand, version control, and deploy across multiple hypervisors. The approach is simple – define the bridge device in a .netdev file, bind the physical interface to it with a .network file, and configure addressing on the bridge with another .network file. Once active, VMs attached to the bridge get direct Layer 2 access to your physical network, exactly like they would with Network Manager but with less overhead.

LEAVE A REPLY

Please enter your comment!
Please enter your name here