Mastering systemd-networkd: The Minimalist’s Guide to Linux Networking

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

Cutting the Fat: Why Minimalist Networking Matters

Most modern Linux distributions ship with surprisingly heavy networking stacks. If you’ve ever spent twenty minutes debugging a YAML indentation error in Netplan or waited for NetworkManager to initialize on a headless server, you’ve felt the bloat. While NetworkManager is great for laptops jumping between Wi-Fi signals, it often consumes 30MB to 50MB of RAM—a significant tax on small IoT devices or lean VPS instances.

These high-level tools are essentially wrappers. When a connection drops, you end up troubleshooting the wrapper instead of the actual network stack. systemd-networkd changes that. It is a native, built-in service that manages configurations directly. It’s incredibly lightweight, typically using less than 8MB of memory and starting in a fraction of a second.

I’ve found that switching to systemd-networkd is a game-changer for high-density environments. On a fleet of 500 Raspberry Pi nodes, this transition reduced boot times by an average of 4 seconds per device. It provides a level of predictability that bulky managers simply can’t match.

The Three Pillars: How systemd-networkd Thinks

Understanding the logic of systemd-networkd is easier than memorizing complex CLI flags. Forget databases or hidden scripts. This daemon relies on simple text files located in /etc/systemd/network/.

You only need to master three file types:

  • .link: These handle low-level hardware matching. Use them if you need to rename eth0 to something specific based on a MAC address.
  • .netdev: These create virtual devices. If you need a Bridge for containers or a VLAN tag, start here.
  • .network: This is your daily driver. It defines how an interface actually behaves, covering DHCP, Static IPs, and routing.

The system processes these files in lexical order. A file named 10-static.network takes priority over 20-dhcp.network. Once an interface matches a pattern in an earlier file, the system stops looking. It’s a simple hierarchy that prevents configuration conflicts.

Migration Guide: Transitioning Your System

Let’s move from theory to implementation. We will disable your current manager and move to a clean, high-performance setup.

Step 1: Clear the Path

Before firing up systemd-networkd, you must stop other services from competing for control of your hardware. On Ubuntu or Debian, NetworkManager is usually the primary culprit.

# Stop and disable the heavy hitters
sudo systemctl stop NetworkManager
sudo systemctl disable NetworkManager

# Netplan users: We will bypass Netplan entirely by writing 
# native systemd configuration files.

Step 2: Identify Your Hardware

You need the exact name of your interface. Run ip link to see what the kernel has detected.

ip link show

Look for names like enp3s0 or eth0. For the following examples, we will use enp3s0.

Step 3: Setting a Static IP

Create a new configuration file. Using a numbered prefix ensures you can control the priority of multiple files later.

sudo nano /etc/systemd/network/10-static-enp3s0.network

Insert the following configuration:

[Match]
Name=enp3s0

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

This tells the system to grab enp3s0, assign it a fixed IP, and route traffic through Google and Cloudflare DNS servers.

Step 4: The “Set and Forget” DHCP Setup

If you prefer your router to handle IP assignments, the config is even shorter. Create /etc/systemd/network/20-dhcp-wired.network:

[Match]
Name=enp*

[Network]
DHCP=yes

The wildcard enp* is a powerful trick. It applies this rule to any Ethernet port starting with those letters, making your configuration portable across different hardware models.

Step 5: Building a Bridge for Virtualization

If you run LXC containers or KVM virtual machines, you need a bridge. Traditionally, this required the brctl tool and messy scripts. With systemd-networkd, it’s a clean two-step process.

First, define the bridge device in /etc/systemd/network/25-br0.netdev:

[NetDev]
Name=br0
Kind=bridge

Next, bind your physical port to that bridge in /etc/systemd/network/30-bind-br0.network:

[Match]
Name=enp3s0

[Network]
Bridge=br0

Step 6: Activation

Now, start the daemon. You should also enable systemd-resolved to handle DNS logic properly.

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

# Link the resolved stub to /etc/resolv.conf for legacy app support
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

Verification and Troubleshooting

Check your work using networkctl. It’s much more informative than the old ifconfig.

networkctl status
networkctl list

If the status shows “routable” and “configured,” your setup is healthy. If you hit a snag, check the logs. Since this is a native systemd service, all network events are captured in the central journal.

journalctl -u systemd-networkd -f

The Bottom Line

Switching to systemd-networkd might feel like a leap if you’re used to GUI tools. However, the performance gains are undeniable. It strips away the “black box” layer of networking and gives you direct, predictable control. By using simple text files and native services, you build a system that is faster to boot, easier to automate, and significantly simpler to maintain over time.

Share: