Hetzner Vswitch/VLAN Configuration
March 1, 2026
The goal here is to create a vswitch at hetzner, lease a subnet for that vswitch, attach a server to the vswitch, and use those addresses on the server for virtual machines. This setup means you can changes the server behind the VMS over time without needing to change the ip addresses.
Testing
ip link add link enp4s0 name enp4s0.4040 type vlan id 4040
ip link set enp4s0.4040 mtu 1400
ip link set dev enp4s0.4040 up
# routing
ip addr add 203.0.113.170/29 dev enp4s0.4040
ip rule add from 203.0.113.170 lookup vswitch
ip rule add to 203.0.113.170 lookup vswitch
ip route add default via 203.0.113.169 dev enp4s0.4040 table vswitch
You can test this with a ping. -I specifies which interface to use (in this case to test our outgoing connection.
# from host
ping -i enp4s0.4040 8.8.8.8
# from another host
ping ADDR
Scripted
If you want to put it together for say a whole subnet of addresses in a script, try the following
#!/bin/bash
#### BEGIN VARS ####
VLAN_ID=4040
NIC=enp4s0
IPS="203.0.113.170/29 203.0.113.171/29 203.0.113.172/29 203.0.113.173/29 203.0.113.174/29"
GW="203.0.113.169"
#### END VARS ####
VLAN_NIC="$NIC.$VLAN_ID"
for IP_CIDR in $IPS
do
IP=$(echo "$IP_CIDR" | sed 's:/.*::')
echo " * Procesing $IP"
echo " * adding to $VLAN_NIC"
ip link add link enp4s0 name "$VLAN_NIC" type vlan id "$VLAN_ID" 2>/dev/null
ip link set "$VLAN_NIC" mtu 1400
ip link set dev "$VLAN_NIC" up
# routing
echo " * adding to $IP to $VLAN_NIC"
ip addr add "$IP_CIDR" dev "$VLAN_NIC"
echo " * adding to route for $IP"
ip rule add from "$IP" lookup vswitch
ip rule add to "$IP" lookup vswitch
ip route add default via "$GW" dev "$VLAN_NIC" table vswitch 2>/dev/null
done
exit 0
Change the four variables to match your physical adapter, IP CIDR addresses, gateway and VLAN ID.
Permanent Configuration
Here is the code to make the changes permanent in /etc/conf.d/net.
vlans_enp4s0="4040"
config_enp4s0_4040="
203.0.113.170/29
203.0.113.171/29
203.0.113.172/29
203.0.113.173/29
203.0.113.174/29
"
mtu_enp4s0_4040="1400"
rules_enp4s0_4040="
from 203.0.113.168/29 table 1
to 203.0.113.168/29 table 1"
routes_enp4s0_4040="default via 203.0.113.169 table 1"
Phew! Now you can easily migrate an manage a set of static ips across any servers at Hetzner.