Configuring Static and Dynamic Networking with systemd-networkd
Manage Linux network config with systemd-networkd .network and .netdev files instead of legacy ifupdown or NetworkManager, with AI help and a human in the loop.
- #linux
- #systemd
- #networking
- #systemd-networkd
I have lost more uptime to a fat-fingered /etc/network/interfaces file than I would like to admit. For years my muscle memory was a tangle of ifup, ifdown, ip route add, and the occasional nmcli incantation that I copied from a Stack Overflow answer at 2 a.m. The day I finally moved a fleet of servers over to systemd-networkd, the thing that surprised me was not the new syntax but how much calmer the whole experience felt. Declarative .network files, a single networkctl reload, and no more wondering whether NetworkManager had silently rewritten my DNS. This is the walkthrough I wish I had when I started, including where I now let an AI assistant speed me up and where I absolutely do not.
Why systemd-networkd at all
If your distribution already ships systemd, you already have systemd-networkd installed; it is just not always enabled. On servers it is a great fit because it is small, predictable, and configured entirely through plain text files that live in /etc/systemd/network/. There is no daemon guessing what you want based on a graphical applet. You write the intent, you reload, you move on.
The contrast with the legacy world matters. ifupdown is imperative and stateful, NetworkManager is fantastic for laptops but heavier than most servers need, and both make automation awkward. systemd-networkd treats the network as configuration-as-code, which means it drops cleanly into Git, Ansible, or whatever pipeline you already run for the rest of your infrastructure.
Enable it with two commands:
sudo systemctl enable --now systemd-networkd
sudo systemctl enable --now systemd-resolved
systemd-resolved handles DNS, and pairing the two gives you a complete stack. Once they are running, networkctl becomes your primary lens into the system.
Reading the current state with networkctl
Before you change anything, look at what you have. networkctl is the diagnostic Swiss Army knife.
networkctl list
That prints every link, its index, type, operational state, and which .network file (if any) currently manages it. For a deeper view of a single interface:
networkctl status eth0
You get the MAC address, assigned IPs, gateway, DNS servers, and the configuration source. When something is wrong, the SETUP field and the unmanaged vs configured state tell you most of the story at a glance. I run networkctl status constantly; it is the equivalent of git status for your network.
Pro Tip: Run networkctl status before and after every change and diff the output in your head. If a field changed that you did not intend to change, stop and investigate before you reload again.
A simple DHCP client
Most cloud instances just want an address from DHCP. Create /etc/systemd/network/20-wired.network:
[Match]
Name=eth0
[Network]
DHCP=yes
The numeric prefix controls ordering; files are processed in lexical order, so 20- leaves room for more specific rules later. The [Match] section decides which interface this file applies to. You can match on Name=, MACAddress=, Type=, or even globs like Name=en*. The [Network] section is where behavior lives. Setting DHCP=yes requests both IPv4 and IPv6 leases; use DHCP=ipv4 if you want to be explicit.
Apply it without rebooting:
sudo networkctl reload
sudo networkctl reconfigure eth0
reload re-reads the files, and reconfigure reapplies them to a specific link.
Pinning a static address
For database boxes, load balancers, and anything that other systems depend on by IP, static configuration is the rule. Here is /etc/systemd/network/10-static.network:
[Match]
Name=eth0
[Network]
Address=192.0.2.50/24
Gateway=192.0.2.1
DNS=192.0.2.1
DNS=1.1.1.1
[Address]
Address=192.0.2.51/24
[Route]
Destination=10.10.0.0/16
Gateway=192.0.2.254
A few things worth noting. You can set Address= directly inside [Network] for the primary address, and add extra [Address] sections for secondaries. [Route] blocks let you add static routes beyond the default gateway, which is invaluable for reaching a management subnet that hangs off a different next hop. The DNS= lines feed straight into systemd-resolved, so you do not touch /etc/resolv.conf by hand. Confirm resolution is wired up correctly with:
resolvectl status
This is the kind of file I am happy to draft with an AI assistant. Tools like Claude or ChatGPT are genuinely good at remembering whether the key is Gateway or GW and at scaffolding the boilerplate. Treat that output the way you would treat a fast junior engineer’s first pass: useful, plausible, and absolutely requiring review before it touches a real host.
Tagged VLANs with a .netdev file
When you need a VLAN, you describe the virtual device in a .netdev file and then attach it. Create /etc/systemd/network/30-vlan100.netdev:
[NetDev]
Name=vlan100
Kind=vlan
[VLAN]
Id=100
Tell the parent interface about it by adding a VLAN= line to the parent’s .network file:
[Match]
Name=eth0
[Network]
VLAN=vlan100
Then give the VLAN its own address with /etc/systemd/network/31-vlan100.network:
[Match]
Name=vlan100
[Network]
Address=192.0.2.130/24
After sudo networkctl reload, networkctl list should show vlan100 as a configured link. This is exactly the sort of multi-file, easy-to-typo task where a prompt pack tuned for Linux networking saves real time, as long as you read every generated line.
Bonding interfaces into a bridge
Bridges show up constantly once you start running containers or virtual machines. The pattern mirrors the VLAN one. Define the bridge in /etc/systemd/network/40-br0.netdev:
[NetDev]
Name=br0
Kind=bridge
Enslave a physical interface with /etc/systemd/network/41-eth1.network:
[Match]
Name=eth1
[Network]
Bridge=br0
And configure the bridge itself in /etc/systemd/network/42-br0.network:
[Match]
Name=br0
[Network]
DHCP=yes
ConfigureWithoutCarrier=yes
ConfigureWithoutCarrier=yes keeps the bridge happy even when no enslaved port has link yet, which matters during boot ordering. Reload, then verify the topology with networkctl status br0 and check that eth1 reports enslaved.
Pro Tip: Never let an automated pipeline or an AI agent apply a bridge or VLAN change to a remote box over the same interface you are reconfiguring. If the change is wrong you can lock yourself out. Keep a console session or an out-of-band management path open as your safety net.
Keeping a human in the loop
Everything above is configuration-as-code, which is precisely what makes it tempting to fully automate. I encourage that, but with a hard line. AI is a fast junior engineer: it will produce a clean .network file in seconds, and it will just as confidently invent a [Network] key that does not exist. The cost of a hallucinated networking directive is a host you cannot reach.
So I keep the workflow human-gated. Generate drafts in a sandbox using Cursor, GitHub Copilot, or a local model like Gemma when I want everything to stay on my own hardware. Review the diff. Test on a throwaway VM. Only then promote it. And I never, ever hand an AI assistant production credentials or live SSH access to do the apply step itself. The model proposes; a human disposes. If you want a structured place to run that review loop, our code review dashboard and incident response dashboard are built around exactly this keep-the-human-in-the-loop pattern, and the broader Linux admin guides collect more of these workflows.
Conclusion
systemd-networkd turns network configuration into something you can read, diff, and reason about. Start by enabling the service, learn networkctl status and networkctl reload cold, and build up from a simple DHCP .network file to static addresses, VLANs, and bridges as your needs grow. Lean on AI to draft the boilerplate fast, but verify every directive yourself and keep production credentials out of the model’s hands. Get those habits right and the 2 a.m. networking panics become a memory rather than a recurring event.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.