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
eth0to 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.

