Proxmox LXC & ZeroTier

mck3nna

New Member
Jul 6, 2025
6
2
3
Hallo zusammen,


ich wende mich nach tagelanger, erschöpfender Fehlersuche an die Community. Ich versuche, einen Roon-Musikserver (LXC) über ZeroTier erreichbar zu machen, stoße aber auf ein Konnektivitätsproblem, das nachweislich im Kernel-Netzwerkstack des Proxmox-Hosts liegt und selbst bei Verwendung des Proxmox SDN-Frameworks besteht.


1. Zielsetzung & Anforderungen


  1. Ziel: Ein LXC-Container soll simultan über das physische LAN (192.168.178.0/24) und ein ZeroTier-Netzwerk (10.x.x.x/16) erreichbar sein.
  2. Anforderung (Nicht verhandelbar): Der Dienst muss aus Performance-Gründen in einem LXC-Container verbleiben. Ein Wechsel zu einer VM ist keine Option.

2. Systemumgebung


  • Host-Hardware: Lenovo Mini-PC
  • Hypervisor: Proxmox VE 8.4.1 (Kernel: 6.8.x) mit physischer NIC eno1.
  • Host-IP (LAN): 192.168.178.x/24 (auf vmbr0)
  • LXC-Container (ID 100): DietPi (Debian 12 basiert), für Roon Core.
  • Router: AVM Fritz!Box 7590
  • ZeroTier-Netzwerk: ID [ZT_NETWORK_ID], Subnetz 10.x.x.x/16

3. Das Kernproblem in Kürze


Egal ob eine manuelle L2-Bridge oder das Proxmox SDN verwendet wird, der Zugriff über ZeroTier schlägt mit "Request Timeout" fehl. Eine tcpdump-Analyse beweist, dass der Proxmox-Host die Pakete vom ZeroTier-Netzwerk empfängt, sie aber intern verwirft, bevor sie die virtuelle Netzwerkschicht zum LXC erreichen.




4. Chronologischer und thematischer Ablauf der Fehlersuche


Versuch 1: Der "saubere" manuelle L2-Bridge-Aufbau


  1. Host-Konfiguration (pve):
    • ZeroTier-Client auf dem Host installiert, Netzwerk beigetreten, "Allow Ethernet Bridging" aktiviert.
    • Eine neue Linux Bridge vmbr1 (ohne IP/Ports) wurde erstellt.
    • Ein systemd-Timer hängt das ZT-Interface (zt-bridge-if) zuverlässig an vmbr1 an. brctl show bestätigt den Erfolg.
  2. LXC-Konfiguration (ID 100):
    • Zwei Netzwerkkarten zugewiesen: net0 an vmbr1 (ZT-IP), net1 an vmbr0 (LAN-IP).
    • ip a im LXC bestätigt, dass beide Interfaces UP sind und die korrekten IPs haben.
  3. Testergebnis & Forensischer Beweis:
    • ping [LAN_IP_LXC] aus dem LAN: ERFOLGREICH.
    • ping [ZT_IP_LXC] von einem Remote-Client: FEHLGESCHLAGEN (Request Timeout).
    • Der tcpdump-Beweis: Ein simultaner Paket-Mitschnitt wurde auf dem Host gestartet:
      • tcpdump -i zt-bridge-if -n icmp: Zeigte die ankommenden ICMP "echo request"-Pakete.
      • tcpdump -i vmbr1 -n icmp: Zeigte KEINERLEI Pakete.
    • Schlussfolgerung: Der Kernel empfängt die Pakete, verwirft sie aber, bevor sie die Bridge erreichen.

Versuch 2: Systematische Firewall-Deaktivierung


  • Aktion: Alle bekannten Firewalls wurden deaktiviert: Proxmox Global, Proxmox LXC-Interface-Checkboxen und ufw im Gast.
  • Ergebnis: Keine Veränderung.

Versuch 3: Tiefgreifendes Host-Kernel-Debugging


  • Aktion 1 (Bridge Netfilter): net.bridge.bridge-nf-call-iptables wurde via sysctl auf 0 gesetzt.
  • Aktion 2 (Hardware Offloading): tso, gso, gro wurden auf der physischen NIC eno1 mit ethtool -K deaktiviert.
  • Aktion 3 (Hairpin Mode): Der Versuch, den hairpin mode zu aktivieren, wurde vom Kernel mit RTNETLINK answers: Operation not supported abgelehnt, was auf eine Limitierung im Bridge-Modul hindeutet.

Versuch 4: Verwendung des Proxmox SDN (Software-Defined Network)


Um einen manuellen Konfigurationsfehler auszuschließen, wurde das integrierte SDN-Framework von Proxmox getestet.


  • Aktion 1 (SDN-Einrichtung): Eine Simple Zone und ein VNet mit eigenem Subnetz (z.B. 10.10.10.0/24) wurden im SDN-Menü erstellt.
  • Aktion 2 (LXC-Konfiguration): Dem LXC wurde eine Netzwerkkarte zugewiesen, die direkt an das neue SDN-VNet angeschlossen war.
  • Aktion 3 (Routing): ZeroTier wurde auf dem Host installiert und eine "Managed Route" in ZeroTier Central für das SDN-Subnetz (10.10.10.0/24) via Host-ZT-IP eingerichtet. IP-Forwarding wurde auf dem Host aktiviert.
  • Ergebnis: Identisches Fehlerbild. Ein Ping von einem externen ZT-Client auf die SDN-IP des LXC (10.10.10.x) schlug fehl.
  • Schlussfolgerung: Das Problem ist fundamentaler Natur und nicht auf eine fehlerhafte manuelle Konfiguration zurückzuführen. Selbst die Proxmox-eigene Abstraktionsebene scheitert.

Versuch 5: Alternative Architekturen & ZT-Dienst-Validierung


  • 5a) ZeroTier direkt im LXC: Führt zu Destination Host Unreachable.
  • 5b) Windows-VM als L3-Router: Selbst eine Windows-VM auf demselben Host zeigt das identische Fehlerbild.
  • 5c) Validierung der Peer-Verbindungen: zerotier-cli peers auf dem Host zeigt für alle relevanten Peers den Status DIRECT. Dies schließt externe Netzwerkprobleme (Router-NAT, ISP-Blockaden) als Ursache aus.



5. Zusammenfassung der Erkenntnisse & die zentrale Frage


  1. Die Konfiguration ist korrekt, egal ob manuell oder via Proxmox SDN.
  2. Das Problem ist keine Firewall.
  3. Beweis 1: tcpdump belegt, dass der Proxmox-Host Pakete vom ZT-Interface empfängt, aber nicht an die virtuelle Netzwerkschicht (Bridge/VNet) weiterleitet.
  4. Beweis 2: Der Kernel meldet, dass der hairpin mode nicht unterstützt wird, was auf eine Limitierung im Bridge-Modul hindeutet.
  5. Beweis 3: Das Problem ist plattform-, nicht gast-spezifisch und tritt auch bei Verwendung des Proxmox SDN auf.
  6. Gegenprobe: Eine andere VPN-Lösung (Tailscale) funktioniert aus demselben LXC heraus einwandfrei.

Meine Frage an die Experten:


Angesichts dieser erdrückenden Beweislast, die auf ein Problem im Proxmox-Kernel-Netzwerkstack hindeutet:


  • Ist dies ein bekannter Bug in der Bridge- oder VNet-Implementierung des Proxmox-Kernels 6.8.x im Zusammenspiel mit virtuellen Interfaces wie denen von ZeroTier?
  • Gibt es eine Möglichkeit, die fehlende Unterstützung für den hairpin mode zu umgehen oder eine alternative Kernel-Einstellung, die den Paketfluss von einem virtuellen Interface zu einer Bridge/VNet erzwingen kann?

Ich bin für jeden tiefgreifenden technischen Einblick dankbar.
 
Wie es so ist, die Behauptung wird nicht bewiesen:
Code:
Anforderung (Nicht verhandelbar): Der Dienst muss aus Performance-Gründen in einem LXC-Container verbleiben. Ein Wechsel zu einer VM ist keine Option.

Wie ich sehe Prosa, sehr viel davon, das mag ich nicht lesen.

Aber, wo sind die realen Netzwerk-Einstellungen, von Proxmox VE host SDN? und des LXC?

Du hast nach meiner Erfahrungen die Probleme einer LXC bzgl. Connectivität nicht im Griff.
 
Proxmox SDN als Simple Network, mach technisch ein SNAT vom Innern Netzwerk (VNET) auf die IP des Proxmox VE Hosts nach außen. Da gibt es kein DNAT, als ein Zugriff von außerhalb des lokalen Netzes auf das SDN Simple Network.
 
Danke für die schnellen Antworten!

@news
"Wie es so ist, die Behauptung wird nicht bewiesen"
was genau meinst du hier? Dass LXC's performanter und ressourcenschonender sind als VM's ist afaik Fakt.

"Du hast nach meiner Erfahrungen die Probleme einer LXC bzgl. Connectivität nicht im Griff."
Das kann gut sein. Welche "Probleme einer LXC bzgl. Connectivität" gibts denn noch?


Hier mal meine Konfogurationsdaten:
1. Proxmox Host (`pve`) - `/etc/network/interfaces`
Code:
auto lo
iface lo inet loopback
iface eno1 inet manual

auto vmbr0
iface vmbr0 inet static
        address 192.168.178.69/24
        gateway 192.168.178.1
        bridge-ports eno1
        bridge-stp off
        bridge-fd 0


2. LXC Container (`100`) - `/etc/pve/lxc/100.conf`
Code:
arch: amd64
cores: 6
features: keyctl=1,nesting=1
hostname: roon
memory: 16384
mp0: /srv/musik,mp=/Musikverzeichnis
net0: name=eth0,bridge=vmbr0,gw=192.168.178.1,hwaddr=BC:24:11:6F:9E:00,ip=192.168.178.70/24,type=veth
onboot: 1
ostype: debian
rootfs: roon:vm-100-disk-0,size=150G
swap: 512
lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file


3. LXC Container (`100`) - `/etc/network/interfaces`
(Hier existiert das `ztrf2vix7s`-Interface, erhält aber keine IP.)
Code:
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 192.168.178.70/24
    gateway 192.168.178.1

# Dieses Interface wird erstellt, erhält aber keine IP
auto ztrf2vix7s
iface ztrf2vix7s inet dhcp


4. LXC Container (`100`) - `iptables-save`
(Die Regeln sind vorhanden, aber wirkungslos, da das ZT-Interface keine IP hat.)
Code:
*filter
:INPUT ACCEPT [X:X]
:FORWARD ACCEPT [X:X]
:OUTPUT ACCEPT [X:X]
-A FORWARD -i ztrf2vix7s -o eth0 -j ACCEPT
-A FORWARD -i eth0 -o ztrf2vix7s -m state --state RELATED,ESTABLISHED -j ACCEPT
*nat
:PREROUTING ACCEPT [X:X]
:INPUT ACCEPT [X:X]
:OUTPUT ACCEPT [X:X]
:POSTROUTING ACCEPT [X:X]
-A POSTROUTING -o eth0 -j MASQUERADE


Gibts sonst noch was, was ich übersehen haben könnte?



Danke für den Hinweis zum SDN!
 
Danke für die ausführliche Antwort.
Jetzt sehe ich den Weg der Pakete.

Ich habe dieses Setting gefunden:
Code:
lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net dev/net none bind,create=dir

Bitte teste das in deiner LXC.

ich hätte auf ein Fehlen eines Parameters abgezielt:
Code:
features: nesting=1

Der ist da, somit kann man auch mit der Welt kommunizieren.
 
Last edited:
Danke für den Link!

Hatte bereits "create=dir" und "create=file" ausprobiert gehabt.

Ich hab vorsichtshalber einen komplett neuen LXC-Container (ID 102) mit einem sauberen, standardmäßigen debian-12-standard-Template erstellt, falls es an "Diet-Pi" liegen könnte.

102.conf:
Code:
  GNU nano 7.2                                                     /etc/pve/lxc/102.conf                                                               
arch: amd64
cores: 2
hostname: roon-debian
memory: 2048
net0: name=eth0,bridge=vmbr0,firewall=1,gw=192.168.178.1,hwaddr=BC:24:11:6C:00:45,ip=192.168.178.70/24,type=veth
ostype: debian
rootfs: roon:vm-102-disk-0,size=32G
swap: 512
unprivileged: 1
features: keyctl=1,nesting=1
lxc.apparmor.profile: unconfined
lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net dev/net none bind,create=dir

pve:
  • chown 100000:100000 /dev/net/tun ausgeführt
  • Teilerfolg. Das zt...-Interface wurde im neuen Debian-Container korrekt erstellt und die Rechte waren korrekt (ls -l /dev/net/tun zeigte root root).
  • Der ZeroTier-Dienst konnte dem Interface keine IPv4-Adresse zuweisen
lxc (debian):
  • Habe daraufhin versucht manuell eine IPv4 Adresse zuzuweisen (Die selbe, die ich dem client in den ZeroTier Admin-Settings gegeben habe)
  • Code:
    ip link set zt... up
    ip addr add 172.22.1.1/16 dev zt...
  • ip a zeigte die korrekte IP, und ip r zeigte die korrekte Route für das ZeroTier-Netz.
  • iptables-Firewall komplett geöffnet um sicher zu gehen
  • Code:
    iptables -P FORWARD ACCEPT
    iptables -F FORWARD

Ergebnis:
  • Vom MacBook (via iPhone-Hotspot) zum LXC: weiterhin "Request Timeout"
  • Vom LXC zum MacBook oder irgend einem anderen Mitglied vom ZeroTier Netzwerk: "Destination Host Unreachable"
 
Ich habe es endlich zum laufen bekommen!

Ich hatte alles wieder zurückgesetzt:
- pve
- LXC (diet-pi)
- LXC (debian)


Habe nach dem aufräumen noch ein letztes mal "https://pve.proxmox.com/wiki/OpenVPN_in_LXC" probiert, leider ohne erfolg.

Hab danach aber glücklicherweise noch weiter rumprobiert:

Auf dem pve:
  • Code:
    # Erstellt das TAP-Device auf dem Host mit den korrekten Major/Minor-Nummern
    mkdir -p /dev/net
    mknod /dev/net/tap c 10 229
    
    # Setzt die Berechtigungen, damit der unprivilegierte LXC darauf zugreifen kann
    chown 100000:100000 /dev/net/tap
    chmod 755 /dev/net # Stellt sicher, dass das Verzeichnis zugreifbar ist
    
    nano /etc/pve/lxc/102.conf
  • Code:
    arch: amd64
    cores: XXX
    features: keyctl=1,nesting=1  # Notwendige Kernel-Features
    hostname: XXX
    memory: XXX
    
    # ABSOLUT WICHTIG: Die net0-Zeile darf hier keine IP-Adresse oder Gateway enthalten. Proxmox soll eth0 nur als "virtuelle Hardware" bereitstellen. Die IP-Konfiguration erfolgt ausschließlich in der Bridge im Container.
    net0: name=eth0,bridge=vmbr0,firewall=1,type=veth,hwaddr=BC:24:11:6C:00:45
    ostype: debian
    rootfs: XXX
    swap: XXX
    
    unprivileged: 1 # Container MUSS unprivilegiert sein
    
    # Zugriff auf das TAP-Device erlauben (c 10:229 ist TAP, 10:200 wäre TUN)
    lxc.cgroup2.devices.allow: c 10:229 rwm
    
    # Mountet das TAP-Device vom Host in den Container. create=dir/file ist wichtig!
    lxc.mount.entry: /dev/net/tap dev/net/tap none bind,create=file,optional,create=dir 0 0

im lxc:
  • systemctl disable --now systemd-networkd.service systemd-networkd.socket
  • nano /etc/network/interfaces
  • Code:
    auto lo
    iface lo inet loopback
    
    # eth0 wird jetzt ein "dummer Port" der Bridge. Keine eigene IP-Konfiguration hier!
    auto eth0
    iface eth0 inet manual
    
    # br0 ist der Chef. Hier bekommt der Container seine IP und sein Gateway.
    auto br0
    iface br0 inet static
        bridge_ports eth0
        address 192.168.178.102/24 # Die LAN-IP des Containers
        gateway 192.168.178.1
        bridge_stp off
        bridge_fd 0
  • reboot
  • curl -s https://install.zerotier.com | bash
  • zerotier-cli join <NETWORK_ID>
  • Code:
    mkdir -p /var/lib/zerotier-one/networks.d
    echo '#!/bin/sh' > /var/lib/zerotier-one/networks.d/<NETWORK_ID>.conf
    echo 'brctl addif br0 $ZT_INTERFACE' >> /var/lib/zerotier-one/networks.d/<NETWORK_ID>.conf
    chmod +x /var/lib/zerotier-one/networks.d/<NETWORK_ID>.conf
  • reboot

ZeroTier-Admin Settings (my.zerotier.com):
  • den Client autorisieren, feste IP vergeben (z.B. 172.22.1.1) und "Allow Ethernet Bridging" aktivieren
  • Managed Route zum lokalen LAN:
    • 1:
      • Route für das ZeroTier-Netzwerk selbst, z.B. 172.22.0.0/16, ohne Gateway
    • 2:
      • Destination: 192.168.178.0/24
      • Via (Gateway): Die ZeroTier-IP des Bridge-Containers (z.B. 172.22.1.1)

DANN konnte ich aus meinem LXC heraus andere Clients aus dem ZeroTier-Netzwerk anpingen!


Zum Glück habe ich das ganze erst auf dem Debian-Container probiert. Als ich das ganze für den eigentlichen LXC mit roon, der mit diet-pi läuft) replizieren wollte, stieß ich auf mehrere Probleme mit dem interface.


Bei meinem MacBook aber ist mir aufgefallen, dass ich den LXC aber immer noch nicht anpingen konnte.
Analyse mit netstat -rn hat aufgedeckt, dass alte virtuelle Interfaces (z. B. bridge0, bridge100, mehrere utun) noch vorhanden waren, obwohl Docker Desktop und VPNs nicht mehr liefen.


---

Falls also jemand ZeroTier auf einem LXC zum laufen bringen möchte, sollte er "Debian" statt "Diet-Pi" nutzen, und die Einstellungen die ich beschrieben habe verwenden.
 
  • Like
Reactions: Johannes S and news
Vielen Dank für die ausführliche Beschreibung und viel Erfolg in der täglichen Arbeit mit den ZeroTier Netzwerk.
 
Last edited:
Nehme alles wieder zurück.
Gestern hats noch funktioniert, heute läuft nichts mehr.
Keine ahnung hab alles probiert.
 
läuft jetzt wieder, vorerst.
pve:
Code:
bash
mknod /dev/net/tun c 10 200
chown 100000:100000 /dev/net/tun
chmod 666 /dev/net/tun

/etc/pve/lxc/<container-nr>.conf
Code:
conf
unprivileged: 1
features: keyctl=1,nesting=1
net0: name=eth0,bridge=vmbr0,firewall=1,type=veth
lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net dev/net none bind,create=dir 0 0

lxc:
/etc/network/interfaces
Code:
conf
auto eth0
iface eth0 inet manual
auto br0
iface br0 inet static
 bridge_ports eth0
 address 192.168.178.102/24
 gateway 192.168.178.1
 bridge_stp off
 bridge_fd 0

proxmox-webGUI:
Datacenter → Firewall → Optionen → ebtables = Aus