Übersicht
Dieser Artikel zeigt, wie man einen dedizierten Root-Server mit statischer IP-Adresse (z. B. bei Hetzner, IONOS oder Netcup) so konfiguriert, dass der gesamte VM-Datenverkehr über eine pfSense/OPNsense-Firewall läuft, mit nur einer einzigen öffentlichen IP-Adresse. Die Proxmox-GUI ist danach nicht mehr direkt aus dem Internet erreichbar und wird über einen lokalen SSH-Tunnel aufgerufen.
Netzwerk-Architektur
Die Lösung basiert auf drei Bridges:
- vmbr0: WAN-Bridge mit öffentlicher IPv4/IPv6
- vmbr1: Transit-Bridge (10.0.10.0/30) für pfSense-WAN
- vmbr2: LAN-Bridge für pfSense und VMs
Eingehender Verkehr wird per DNAT zur WAN-Schnittstelle weitergeleitet (ausgenommen SSH Port 22). Ausgehender Verkehr wird per Masquerading genattet.

Schritt 1: IP-Adressen ermitteln
# Interface setzen (bei Hetzner meist eno1)
IFACE=eno1
# IPv4-Adresse
ip -o -4 addr show dev "$IFACE" | awk '{print "address "$4}'
# IPv6-Adresse (ohne fe80::)
ip -o -6 addr show dev "$IFACE" | awk '$4 !~ /^fe80::/ {print "address "$4}'
# Default-Gateways
ip route | awk -v d="$IFACE" '$1=="default" && $5==d {print "gateway "$3; exit}'
ip -6 route | awk -v d="$IFACE" '$1=="default" && $5==d {print "gateway "$3; exit}'
Schritt 2: /etc/network/interfaces konfigurieren
Die Platzhalter mit den in Schritt 1 ermittelten Werten ersetzen. Die IPv6-Zeilen sind auskommentiert und werden nur benotigt wenn ein geroutetes IPv6-Subnetz vorhanden ist (siehe optionaler Abschnitt weiter unten).
source /etc/network/interfaces.d/*
auto lo
iface lo inet loopback
auto eno1
iface eno1 inet manual
auto vmbr0
iface vmbr0 inet static
address /
gateway
bridge-ports eno1
bridge-stp off
bridge-fd 0
bridge-maxwait 0
# Optional: IPv6 -- siehe Abschnitt weiter unten
#iface vmbr0 inet6 static
# address /64
# gateway fe80::1
post-up echo 1 > /proc/sys/net/ipv4/ip_forward
auto vmbr1
iface vmbr1 inet static
address 10.0.10.1/30
bridge-ports none
bridge-stp off
bridge-fd 0
# DNAT: alle TCP-Verbindungen ausser SSH an pfSense weiterleiten
post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp ! --dport 22 -j DNAT --to-destination 10.0.10.2
post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp ! --dport 22 -j DNAT --to-destination 10.0.10.2 || true
# Masquerading fuer ausgehenden Traffic vom Transit-Netz
post-up iptables -t nat -A POSTROUTING -s '10.0.10.0/30' -o vmbr0 -j MASQUERADE
post-down iptables -t nat -D POSTROUTING -s '10.0.10.0/30' -o vmbr0 -j MASQUERADE || true
# Optional: IPv6 -- siehe Abschnitt weiter unten
#iface vmbr1 inet6 static
# address fd00:10::1/64
#
# post-up sysctl -w net.ipv6.conf.all.forwarding=1
# post-up sysctl -w net.ipv6.conf.default.forwarding=1
#
# post-up ip -6 route replace /64 via fd00:10::2 dev vmbr1
# post-down ip -6 route del /64 || true
#
# post-up ip6tables -C FORWARD -i vmbr1 -o vmbr0 -j ACCEPT 2>/dev/null || ip6tables -A FORWARD -i vmbr1 -o vmbr0 -j ACCEPT
# post-up ip6tables -C FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || ip6tables -A FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT
# post-down ip6tables -D FORWARD -i vmbr1 -o vmbr0 -j ACCEPT 2>/dev/null || true
# post-down ip6tables -D FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
auto vmbr2
iface vmbr2 inet static
address /24
bridge-ports none
bridge-stp off
bridge-fd 0
bridge-vlan-aware yes
bridge-vids 2-4094
Schritt 3: System neu starten
/usr/sbin/reboot
Konfiguration bei pfSense/OPNsense
WAN-Interface
Unter Interfaces → WAN: IPv4 auf Static setzen, Adresse 10.0.10.2/30, Gateway 10.0.10.1. Die Optionen Block private networks und Block bogon networks deaktivieren, da die WAN-IP eine private Transit-Adresse ist.
IPv6 optional: Static fd00:10::2/64, Gateway fd00:10::1.

LAN-Interface
Unter Interfaces → LAN: IPv4 Static, z. B. 192.168.10.254/24. Weitere Subnetze als OPT-Interfaces hinzufugen.
DHCP
Unter Services → DHCP Server pro Interface aktivieren, Range und Gateway eintragen. Als DNS-Server entweder die pfSense-IP (DNS Resolver) oder direkt externe Server wie 1.1.1.1.

Outbound NAT
Unter Firewall → NAT → Outbound den Modus auf Hybrid stellen. Alle internen Subnetze gehen per Masquerade uber das WAN raus.

Optional: Geroutetes IPv6-Subnetz für VMs (Hetzner)
Jeder Hetzner Dedicated Server kommt mit einem /64-Subnetz für den Host selbst. Damit VMs öffentliche IPv6-Adressen erhalten, muss im Hetzner Robot unter IPs / Subnets ein zusätzliches geroutetes /64 bestellt werden.
Die in Schritt 2 auskommentierten IPv6-Zeilen müssen dazu einkommentiert werden. Die vollständige Konfiguration mit IPv6:
source /etc/network/interfaces.d/*
auto lo
iface lo inet loopback
iface lo inet6 loopback
auto eno1
iface eno1 inet manual
auto vmbr0
iface vmbr0 inet static
address /
gateway
bridge-ports eno1
bridge-stp off
bridge-fd 0
bridge-maxwait 0
iface vmbr0 inet6 static
address /64
gateway fe80::1
post-up echo 1 > /proc/sys/net/ipv4/ip_forward
auto vmbr1
iface vmbr1 inet static
address 10.0.10.1/30
bridge-ports none
bridge-stp off
bridge-fd 0
# DNAT: alle TCP-Verbindungen ausser SSH an pfSense weiterleiten
post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp ! --dport 22 -j DNAT --to-destination 10.0.10.2
post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp ! --dport 22 -j DNAT --to-destination 10.0.10.2 || true
# Masquerading fuer ausgehenden Traffic vom Transit-Netz
post-up iptables -t nat -A POSTROUTING -s '10.0.10.0/30' -o vmbr0 -j MASQUERADE
post-down iptables -t nat -D POSTROUTING -s '10.0.10.0/30' -o vmbr0 -j MASQUERADE || true
iface vmbr1 inet6 static
address fd00:10::1/64
post-up sysctl -w net.ipv6.conf.all.forwarding=1
post-up sysctl -w net.ipv6.conf.default.forwarding=1
post-up ip -6 route replace /64 via fd00:10::2 dev vmbr1
post-down ip -6 route del /64 || true
post-up ip6tables -C FORWARD -i vmbr1 -o vmbr0 -j ACCEPT 2>/dev/null || ip6tables -A FORWARD -i vmbr1 -o vmbr0 -j ACCEPT
post-up ip6tables -C FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || ip6tables -A FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT
post-down ip6tables -D FORWARD -i vmbr1 -o vmbr0 -j ACCEPT 2>/dev/null || true
post-down ip6tables -D FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
auto vmbr2
iface vmbr2 inet static
address /24
bridge-ports none
bridge-stp off
bridge-fd 0
bridge-vlan-aware yes
bridge-vids 2-4094
pfSense erhält auf dem Transit-Interface die Adresse fd00:10::2/64 mit Gateway fd00:10::1. Das geroutete /64 wird auf dem LAN-Interface verteilt, entweder statisch oder per DHCPv6/SLAAC.
Zugriff auf die Proxmox-GUI via SSH-Tunnel
Da Port 8006 nicht direkt erreichbar ist, wird die GUI über einen lokalen SSH-Tunnel aufgerufen:
ssh -L 8006:localhost:8006 root@<server-ip>
Danach im Browser https://localhost:8006 aufrufen.
Eine einzige öffentliche IP-Adresse genügt für ein vollständiges Firewall-Setup mit VM-Isolation auf Proxmox.