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.