Mastering systemd-networkd on Linux: Static IP, DHCP, VLAN, and Bridge Guide

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Approach Comparison: systemd-networkd vs. ifupdown vs. Netplan

Linux network configuration has felt fragmented for years. Different distributions have pushed competing tools to solve the exact same fundamental tasks: assigning IP addresses, setting up routing tables, and configuring virtual interfaces.

Debian environments historically depended on ifupdown via /etc/network/interfaces. It is straightforward, but it relies heavily on shell scripts. As a result, it struggles with hotplugged NICs, dynamic link state changes, and native systemd service ordering.

Canonical built Netplan for Ubuntu to unify configurations under clean YAML files in /etc/netplan/. Yet Netplan is strictly a generator, not a network daemon. When things break, you end up debugging both your YAML indentation and the generated backend files parked in /run/systemd/network/.

NetworkManager remains the standard choice for workstations and laptops. It handles erratic Wi-Fi handoffs, mobile broadband modems, and VPNs without fuss. However, on headless servers and minimal containers, its D-Bus daemon and ~30 MB memory footprint add bloat you rarely need.

systemd-networkd eliminates those extra layers. Sitting directly inside the systemd tree, it uses declarative .netdev and .network unit files in /etc/systemd/network/. It controls the Linux kernel’s rtnetlink subsystem directly—no wrappers, no intermediate YAML parsers, and a tiny memory footprint of just 4–8 MB.

Pros and Cons of systemd-networkd

Switching directly to systemd-networkd gives you a predictable, lightweight stack. Still, it helps to weigh its strengths against common production limitations.

Advantages

  • Zero extra packages: If your distribution boots with systemd, networkd is already on disk. You do not need Python runtimes or external helper tools.
  • Lightning-fast boot times: The daemon spawns in early userspace. It configures interfaces asynchronously in parallel, routinely shaving 1.5 to 3 seconds off system boot times.
  • Consistent INI syntax: Network units share the exact same format as your .service, .mount, and .timer units.
  • Native virtual devices: Setting up bridges, VLAN trunks, bonding pairs (LACP), and WireGuard tunnels takes just a few concise declarative lines.

Disadvantages

  • Manual Wi-Fi management: The daemon does not negotiate WPA-PSK or 802.1X out of the box. You must pair it with iwd or wpa_supplicant.
  • No interactive curses UI: There is no direct equivalent to NetworkManager’s nmtui. You write text files by hand.
  • Desktop tray disconnects: Standard desktop applets (such as GNOME Control Center) rely on NetworkManager’s D-Bus API to report link states.

Recommended Architecture: The Three Unit Files

All persistent network configurations live inside /etc/systemd/network/. The daemon parses files in strict lexical order (for instance, 10-eth0.network takes precedence over 99-default.network).

A maintainable deployment relies on three distinct file types:

  • .link: Matches physical hardware properties to adjust MAC addresses, interface names, and MTU before interfaces come up.
  • .netdev: Creates virtual network devices such as software bridges (br0), VLANs (vlan20), and bonded pairs.
  • .network: Defines Layer 3 routing parameters, static IP addresses, DHCP leases, and DNS resolvers.

Step-by-Step Implementation

The following steps walk through transitioning an interface to systemd-networkd, setting up static and dynamic IPs, and building production VLAN and bridge interfaces.

Step 1: Inspect Current Interfaces

Start by verifying active interface names, MAC addresses, and current IP allocations:

ip -brief link show
ip -brief address show

For this guide, our primary 10GbE physical NIC is ens18.

A quick caution for remote servers: a malformed subnet mask or broken default gateway will cut your SSH session instantly. Always open an out-of-band serial console—such as Proxmox NoVNC, Hetzner Robot vKVM, or AWS Serial Console—before modifying live network units.

Step 2: Disable Conflicting Daemons

Two daemons managing the same physical adapter will cause route flapping. If NetworkManager is running, stop and mask it:

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

If you are on Ubuntu, disable Netplan’s auto-generation by removing any configurations under /etc/netplan/*.yaml or setting the renderer to networkd.

Next, enable and start systemd-networkd along with systemd-resolved for DNS lookups:

sudo systemctl enable --now systemd-networkd
sudo systemctl enable --now systemd-resolved

Step 3: Configure Dynamic IP (DHCP)

To let an interface pick up an address automatically via DHCPv4 and IPv6 SLAAC/DHCPv6, create a network unit:

sudo nano /etc/systemd/network/10-ens18-dhcp.network

Add the following configuration:

[Match]
Name=ens18

[Network]
DHCP=yes

[DHCPv4]
RouteMetric=100
UseDNS=true

Load the new profile immediately:

sudo networkctl reload
sudo networkctl reconfigure ens18

Step 4: Configure Static IPv4 and DNS

Production servers running databases or web hosts require static, predictable addresses. If you previously created the DHCP profile, remove or rename it so it does not conflict:

sudo rm -f /etc/systemd/network/10-ens18-dhcp.network
sudo nano /etc/systemd/network/10-ens18-static.network

Write your static IP, default route, and DNS settings:

[Match]
Name=ens18

[Network]
Address=192.168.1.50/24
DNS=1.1.1.1 8.8.8.8
Domains=internal.lab

[Route]
Gateway=192.168.1.1
Metric=100

Apply the change and inspect the link state:

sudo networkctl reload
sudo networkctl reconfigure ens18
networkctl status ens18

Step 5: Configure an 802.1Q VLAN Tag

To trunk multiple isolated network segments through a single physical cable, you need two pieces: a .netdev unit to instantiate the virtual sub-interface, and a .network unit to bind that VLAN tag to your physical card.

First, create VLAN 20:

sudo nano /etc/systemd/network/20-vlan20.netdev
[NetDev]
Name=ens18.20
Kind=vlan

[VLAN]
Id=20

Second, inform the base interface ens18 that it carries VLAN 20. Update /etc/systemd/network/10-ens18-static.network:

[Match]
Name=ens18

[Network]
Address=192.168.1.50/24
DNS=1.1.1.1
VLAN=ens18.20

[Route]
Gateway=192.168.1.1
Metric=100

Third, assign an IP address to the newly created ens18.20 virtual interface:

sudo nano /etc/systemd/network/20-vlan20.network
[Match]
Name=ens18.20

[Network]
Address=10.20.0.5/24

Reload systemd-networkd to create the virtual device and bind the address:

sudo networkctl reload
sudo networkctl reconfigure ens18
ip -brief address show ens18.20

Step 6: Build a Software Network Bridge

When hosting KVM virtual machines or LXC containers, you need a software bridge (br0) so guests can communicate directly on the host’s physical LAN segment.

Important: In a bridge topology, your physical adapter acts purely as a pipe (Layer 2). The IP address, gateway, and DNS must attach to the bridge device itself, never to the physical card.

First, create the bridge device br0:

sudo nano /etc/systemd/network/05-br0.netdev
[NetDev]
Name=br0
Kind=bridge

Second, assign ens18 as a member port of br0. Replace the existing 10-ens18-static.network file:

sudo nano /etc/systemd/network/10-ens18-member.network
[Match]
Name=ens18

[Network]
Bridge=br0

Third, assign your static IP parameters directly to the bridge interface:

sudo nano /etc/systemd/network/20-br0.network
[Match]
Name=br0

[Network]
Address=192.168.1.50/24
DNS=1.1.1.1 8.8.8.8

[Route]
Gateway=192.168.1.1
Metric=100

Clear out any orphaned static profiles on ens18 to avoid duplicate routing rules, then reconfigure:

sudo rm -f /etc/systemd/network/10-ens18-static.network
sudo networkctl reload
sudo systemctl restart systemd-networkd
networkctl status br0

Step 7: Everyday Operational Commands

The companion CLI utility networkctl handles daily inspections and status checks:

  • networkctl list: Shows an overview of all physical and virtual interfaces, their operational states (routable, degraded, carrier), and drivers.
  • networkctl status ens18: Outputs comprehensive link stats, MTU values, active DHCP leases, and DNS servers.
  • networkctl reload: Parses changed .network and .netdev files on disk without bouncing existing links.
  • networkctl reconfigure ens18: Forces a specific interface to drop and reapply its current configuration profile.
  • networkctl lldp: Inspects Link Layer Discovery Protocol packets to view upstream switch port information directly from the command line.

Mastering these basic configuration units gives you total visibility over your Linux network stack—without wrapper scripts or unnecessary background services getting in the way.

Share: