TTR Networks

Intermediate · Debian as an office router: interfaces, VLANs and a firewall · section 2 of 8

Interfaces with systemd-networkd

✓ Lab-tested 5 November 2026 on Debian 13.7, systemd 257, nftables 1.1.3

Debian 13 ships with systemd-networkd, a network manager that reads plain configuration files and keeps the interfaces in that state at every boot. It's a good fit for a router: no desktop, no guessing, and the same few file types describe everything.

Three kinds of file

  • .network files match an interface (by name here) and say what to do with it: addresses, gateway, DHCP, and which VLANs ride on it.
  • .netdev files create virtual interfaces, such as VLANs, bridges or WireGuard tunnels.
  • Files are read in name order, so a number prefix (10-, 20-) keeps them tidy and decides which file wins if two match the same interface.

The WAN file gives eth0 a fixed address and the default route. The trunk file gives eth1 no address at all, just the three VLANs it carries; LinkLocalAddressing=no stops it picking up an automatic IPv6 address either. Each VLAN then needs two small files: a .netdev that creates it with its VLAN ID, and a .network that gives it the router's address on that VLAN. The VLAN interfaces are named after their purpose (staff, guest, servers), which makes the firewall rules later read like the policy table.

Turning it on

On a fresh Debian install networkd is installed but disabled. Enable it, and within a second the links go from unmanaged to configured: the WAN and the three VLANs are routable (they have addresses), and the trunk is carrier (up, but deliberately without an address). ip -d link confirms each VLAN interface is an 802.1Q interface on eth1 with the right ID, and ip route has the default route from the WAN file plus a route for each VLAN.

If Debian's installer set up /etc/network/interfaces (ifupdown), remove those interfaces from it, or disable networking.service, before enabling networkd. Two tools configuring the same interface is a reliable way to get confusing results.

/etc/systemd/network/10-wan.network
# The internet side: a fixed address from the ISP.
# (For an address by DHCP instead, replace Address and Gateway with DHCP=ipv4.)
[Match]
Name=eth0

[Network]
Address=203.0.113.2/24
Gateway=203.0.113.1
  • Lines 3–4: Which interface this file is for.
  • Lines 7–8: The ISP's fixed address and gateway: the router's default route.
/etc/systemd/network/20-trunk.network
# The office side: one port to the switch, carrying three VLANs. The port
# itself has no address; each VLAN interface gets its own.
[Match]
Name=eth1

[Network]
VLAN=staff
VLAN=guest
VLAN=servers
LinkLocalAddressing=no
  • Lines 7–9: The VLANs this port carries. Each name must have a matching .netdev file, and a VLAN only exists once it's listed here.
  • Line 10: No automatic link-local address: the trunk port itself is never used for IP.
/etc/systemd/network/30-staff.netdev
# VLAN 10: staff PCs. The router is their gateway, 10.10.10.1.
[NetDev]
Name=staff
Kind=vlan

[VLAN]
Id=10
  • Lines 2–4: Create a VLAN interface called staff…
  • Lines 6–7: …for frames tagged with VLAN 10.
/etc/systemd/network/30-staff.network
[Match]
Name=staff

[Network]
Address=10.10.10.1/24
  • Line 5: The router's address on the staff VLAN: every staff PC's gateway.
/etc/systemd/network/30-guest.netdev
# VLAN 20: guest Wi-Fi. Internet only.
[NetDev]
Name=guest
Kind=vlan

[VLAN]
Id=20
/etc/systemd/network/30-guest.network
[Match]
Name=guest

[Network]
Address=10.10.20.1/24
/etc/systemd/network/30-servers.netdev
# VLAN 30: the office servers.
[NetDev]
Name=servers
Kind=vlan

[VLAN]
Id=30
/etc/systemd/network/30-servers.network
[Match]
Name=servers

[Network]
Address=10.10.30.1/24
Turning networkd on (real output)
root@router:~# networkctl list eth0 eth1; ip -4 -br addr show
IDX LINK TYPE  OPERATIONAL SETUP
 11 eth1 ether -           unmanaged
 12 eth0 ether -           unmanaged

2 links listed.
lo               UNKNOWN        127.0.0.1/8 

root@router:~# ls /etc/systemd/network
10-wan.network
20-trunk.network
30-guest.netdev
30-guest.network
30-servers.netdev
30-servers.network
30-staff.netdev
30-staff.network

root@router:~# systemctl enable --now systemd-networkd
Created symlink '/etc/systemd/system/dbus-org.freedesktop.network1.service' → '/usr/lib/systemd/system/systemd-networkd.service'.
Created symlink '/etc/systemd/system/multi-user.target.wants/systemd-networkd.service' → '/usr/lib/systemd/system/systemd-networkd.service'.
Created symlink '/etc/systemd/system/sockets.target.wants/systemd-networkd.socket' → '/usr/lib/systemd/system/systemd-networkd.socket'.
Created symlink '/etc/systemd/system/sysinit.target.wants/systemd-network-generator.service' → '/usr/lib/systemd/system/systemd-network-generator.service'.
Created symlink '/etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service' → '/usr/lib/systemd/system/systemd-networkd-wait-online.service'.

root@router:~# networkctl list eth0 eth1 staff guest servers; ip -4 -br addr show
IDX LINK    TYPE  OPERATIONAL SETUP
 11 eth1    ether carrier     configured
 12 eth0    ether routable    configured
 13 servers vlan  routable    configured
 14 guest   vlan  routable    configured
 15 staff   vlan  routable    configured

5 links listed.
lo               UNKNOWN        127.0.0.1/8 
eth0@if5285      UP             203.0.113.2/24 
servers@eth1     UP             10.10.30.1/24 
guest@eth1       UP             10.10.20.1/24 
staff@eth1       UP             10.10.10.1/24 

root@router:~# ip -d link show guest | head -3; ip route
14: guest@eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 02:00:00:00:01:01 brd ff:ff:ff:ff:ff:ff promiscuity 0 allmulti 0 minmtu 0 maxmtu 65535 
    vlan protocol 802.1Q id 20 <REORDER_HDR> addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 tso_max_size 524280 tso_max_segs 65535 gro_max_size 65536 gso_ipv4_max_size 65536 gro_ipv4_max_size 65536 
default via 203.0.113.1 dev eth0 proto static 
10.10.10.0/24 dev staff proto kernel scope link src 10.10.10.1 
10.10.20.0/24 dev guest proto kernel scope link src 10.10.20.1 
10.10.30.0/24 dev servers proto kernel scope link src 10.10.30.1 
203.0.113.0/24 dev eth0 proto kernel scope link src 203.0.113.2 
  • Lines 1–7: Before: networkd isn't running, so the ports are unmanaged and have no IPv4 addresses.
  • Lines 19–24: Enabled now and at every boot.
  • Lines 26–32: After: the WAN and the VLANs are routable (they have addresses); the trunk is up but deliberately has none.
  • Lines 36–39: Each VLAN interface sits on eth1 (guest@eth1) with the router's .1 address.
  • Line 44: An 802.1Q VLAN interface with ID 20.
  • Lines 45–49: The default route from the WAN file, and a route for each network.

Check your understanding

The trunk port eth1 has no address. How does the router talk to the staff PCs on it?

  • Through the staff VLAN interface, which has its own address, 10.10.10.1, and handles the frames tagged 10.
  • It can't until eth1 gets an address in 10.10.10.0/24.
  • The switch routes between the VLANs instead.
  • Through eth0, the WAN port.