Ich bin ein Kontroll-Freak. Mein Mesh-VPN sollte es auch sein.

8 min read

Ein privates Mesh-VPN bringt deine gesamte Dev-Infrastruktur ins selbe Netzwerk. VPS-Server, dein Mac, dein Handy. Alles kommuniziert über verschlüsselte Tunnel statt über das offene Internet. Du musst keine SSH-Ports, interne APIs oder Datenbankverbindungen mehr nach außen exponieren. Weniger Angriffsfläche, weniger Risiko, einfachere Firewall-Regeln.

Tailscale macht das gut. Der Tunnel ist P2P, das Setup dauert 30 Sekunden, und du vergisst, dass es da ist. Nur der Koordinationsserver, das Ding, das deinen Maschinen hilft, sich zu finden, läuft auf Tailscales Infrastruktur. Und wenn du Multi-VPS-Produktionsworkloads betreibst, ist "auf deren Infrastruktur" eine Abhängigkeit, für die du dich nie angemeldet hast.

Ich bin schon mal verbrannt worden, als ein Anbieter mitten im Spiel die Regeln für mein Produktionssetup geändert hat. Einmal reicht. Also bin ich zu NetBird gewechselt, komplett selbst gehostet, hinter dem Traefik Reverse Proxy, der bereits auf meinem VPS läuft. Das Mesh selbst hat 2 Minuten pro Client gedauert. Die echte Arbeit war alles andere.

TLDR: NetBird ersetzt Tailscale durch ein vollständig selbst gehostetes WireGuard P2P Mesh. Das Netzwerk steht in 2 Minuten. Aber wenn du bereits Traefik in Produktion hast, ist das offizielle Setup-Script unbrauchbar. Dieser Artikel gibt dir das angepasste docker-compose, das pfadbasierte Routing mit Prioritäten und die 7 Fallstricke, die weder die Docs noch irgendein Tutorial erwähnen.

Comic-Illustration: Überforderter Büroangestellter ertrinkt in Kabeln vs. triumphierender Held auf selbst-gehostetem Server-Rack mit Mesh-Netzwerk-Kontrollpanel
Vendor Lock-in vs. Mesh-VPN-Suprematie: Wähle dein eigenes Abenteuer.

Tailscale funktioniert. Darum geht's nicht.

Tailscale ist wirklich gute Software. Ich hab's monatelang laufen lassen. P2P-Verbindungen über WireGuard, NAT-Traversal, das tatsächlich funktioniert, ein sauberes Admin-Panel. Keine Beschwerden auf der Tunnel-Seite.

Das Problem ist strukturell. Der Koordinationsserver (Tailscale nennt es ihre "Control Plane") ist ein SaaS, das dir nicht gehört. Jedes Mal, wenn deine Maschinen sich finden müssen, telefonieren sie nach Hause. Wenn Tailscale ihre Preise ändert, den kostenlosen Tarif killt oder einen schlechten Tag hat, kann dein privates Netzwerk keine neuen Verbindungen aufbauen. Bestehende Tunnel überleben (sie sind WireGuard darunter), aber keine neuen Peers, kein Re-Keying, keine Änderungen.

Für ein Wochenend-Homelab-Projekt ist das okay. Für Produktions-VPS-Infrastruktur, wo ich Kundendienste betreibe, ist es eine Wette, die ich nicht weiter eingehen will. Keine Paranoia. Nur derselbe Reflex, den jeder Dev bekommt, nachdem er gesehen hat, wie ein Anbieter den Teppich unter den Füßen wegzieht.

Die Lösung war offensichtlich. Die Koordinationsebene selbst hosten.

Ich hab mir jede Alternative angeschaut. Die meisten sind Sackgassen.

Die Shortlist eliminiert sich schnell selbst:

Headscale reverse-engineert das Tailscale-Protokoll. Das heißt, du hängst immer noch von Tailscales Client-Apps ab, und Tailscale hat keine Verpflichtung, ihr Protokoll für einen Drittanbieter-Server stabil zu halten. Die Community hat dieses Risiko ausführlich dokumentiert. Dein selbst gehosteter Koordinationsserver könnte bei jedem Tailscale-Client-Update kaputt gehen, das du nicht kontrollierst.

ZeroTier verwendet ein eigenes Protokoll, nicht WireGuard. Das ist ein Dealbreaker für jeden, der standardisierte, auditierte Krypto darunter will.

Nebula (Slacks Mesh-Tool) hat keinen nativen iOS-Client. Mein Handy ist ein Peer. Nicht verhandelbar.

Netmaker hat dokumentierte Stabilitätsprobleme in Community-Reports. Ich will meine Netzwerkebene nicht debuggen.

Raw WireGuard ist felsenfest, hat aber keine automatische Mesh-Discovery. Du managst manuell Peer-Configs auf jedem Node. Mit 3 Peers ist das nervig. Mit 10 ist es ein Job. Mit 30 ist es ein Karrierewechsel, für den du dich nicht beworben hast.

NetBird ist das, was die Elimination überlebt hat. Vollständig Open Source (Client UND Koordinationsserver, nicht nur eine Seite). Native iOS-App im App Store. WireGuard unter der Haube mit Rosenpass Post-Quantum-Layer obendrauf. Lokales User-Management seit v0.62 (kein externer Identity Provider für kleine Setups nötig). Combined Docker Image, das Management, Signal, Relay und STUN in einem Container bündelt.

Und ja, NetBird ist jünger als Tailscale. Das Drittanbieter-Integrations-Ökosystem ist dünner. Du findest nicht dieselben Plug-and-Play-Konnektoren für jedes SaaS-Tool. Aber ich suche kein Ökosystem. Ich suche ein Mesh, das mir gehört.

Das offizielle Script ist für Leute gebaut, die nichts in Produktion haben.

Ich ging zu den NetBird-Docs. Klickte "Self-hosting." Lud getting-started.sh runter.

Dann sehe ich, dass das Script seine eigene Traefik-Instanz deployed.

Ich habe bereits Traefik v3 auf diesem VPS laufen. Es handhabt Routing für Client-Sites, Apps, Dashboards. Es hat Let's Encrypt-Zertifikate, Middleware-Ketten, das ganze Zeug. Ich reiße das nicht ab und ich lasse nicht zwei Traefik-Instanzen auf derselben Maschine laufen, die sich um Port 443 streiten.

Also wandert das offizielle Script in den Müll und du schreibst dir ein eigenes docker-compose, das NetBirds Services in dein bestehendes Traefik einstöpselt. Und da fängt die echte Arbeit an.

Das Routing ist der knifflige Teil. Alles lebt auf einer einzigen Domain (netbird.yourdomain.com), getrennt durch Pfad und Priorität. Die Logik:

Priorität 100 (höchste): gRPC-Services (Signal und Management API). Diese brauchen das h2c-Schema, weil Traefik TLS terminiert und plain HTTP/2 an die Container weiterleitet. Wenn du http statt h2c verwendest, schlägt gRPC stillschweigend fehl und der Client bleibt bei "Disconnected" hängen.

Priorität 50: WebSocket-Verbindungen für den Relay-Service, REST-API-Endpunkte und OAuth2-Callback-Routen. Standard HTTP, nichts Exotisches.

Priorität 1 (Catch-all): Das Dashboard UI. Alles, was keine höher priorisierte Regel matcht, landet hier.

Coturn (TURN/STUN-Server): Läuft in network_mode: host, komplett außerhalb von Traefik. Es braucht raw UDP auf Ports 3478 und 49152-65535. Kein Reverse Proxy kann dir hier helfen.

Architecture diagram showing Traefik as public-facing gateway (client sites, apps, NetBird dashboard) with path-based routing to NetBird containers behind it. Separate mesh overlay showing 3 peers (VPS Contabo with management server, VPS Hostinger, MacBook) connected P2P via WireGuard tunnels. Coturn bypassing Traefik via direct UDP.
Traefik Gateway mit NetBird P2P Mesh Architektur

Wenn du schon mal Traefik-Routing gemacht hast, ist das vertrautes Terrain. Wenn nicht, hat mich jede dieser Prioritätsstufen eine Runde "warum ist das 502?" gekostet, bis es richtig war.

Die 7 Fallstricke, vor denen mich niemand gewarnt hat

Ich bin während des Dex-Dashboard-Setups sichtbar gealtert. Vier Iterationen am Login-Screen, bevor es funktionierte. Der Großteil meiner 2-Stunden-Einrichtung ging für diese Liste drauf, nicht für das Mesh.

1. exposedAddress braucht den Port.
In config.yaml muss das exposedAddress-Feld für den Signal-Server :443 enthalten. Der gRPC-Client-Parser schlägt mit "missing port in address" fehl, wenn du es weglässt. Der Signal-Service bleibt "Disconnected" ohne brauchbare Fehlermeldungen.

2. Leerer Bildschirm nach Login. Kein Fehler.
Das Dashboard-JavaScript macht window.location.origin + redirectURI. Wenn deine AUTH_REDIRECT_URI eine vollständige URL statt eines relativen Pfads ist, verdoppelt es sich: https://netbird.yourdomain.com/https://netbird.yourdomain.com/nb-auth. Setze es auf /nb-auth, nicht die vollständige Domain. Viel Glück beim Debuggen ohne Quellcode-Lesen.

3. AUTH_CLIENT_ID ist "netbird-dashboard", nicht "dashboard".
Die Dex Static Client Config erwartet netbird-dashboard. Wenn du dashboard verwendest, schlägt die Authentifizierung stillschweigend fehl. Kein Fehler im UI, keine brauchbare Log-Zeile. Du kannst dich einfach nicht einloggen.

4. Dex-Scopes sind nicht Auth0-Scopes.
Die korrekten Scopes für Dex sind openid profile email groups. Wenn du von Auth0-Beispielen copy-pastest (und viele Blog-Posts verwenden Auth0), fügst du api und email_verified hinzu. Diese Scopes existieren in Dex nicht. Die Token-Anfrage schlägt fehl.

5. Container startet, Logs sehen sauber aus, Login funktioniert nicht.
Das Dashboard-Init-Script nimmt standardmäßig Auth0 an. Du brauchst AUTH_SUPPORTED_SCOPES=openid profile email groups und USE_AUTH0=false in den Dashboard-Env-Vars. Ohne beide crasht das Script stillschweigend. Kein Fehler, keine Warnung. Nur eine Login-Seite, die jeden Versuch ablehnt.

6. store.encryptionKey muss in config.yaml stehen.
Ohne ihn generiert der Management-Server beim Start einen zufälligen Key. Starte den Container neu und er kann seine eigenen Daten nicht entschlüsseln. Setze ihn einmal, behalte ihn für immer. (Oder genieße es, jeden Peer nach einem Reboot neu zu registrieren.)

7. Routen, die klar definiert sind, geben 404 zurück.
Du checkst die Label-Syntax. Korrekt. Du checkst den Pfad. Korrekt. Du checkst die Priorität. Korrekt. Stellt sich heraus, Docker Compose YAML und Shell-Heredocs handhaben Backticks unterschiedlich. Wenn deine Traefik-Labels Backtick-delimitierte Path-Matcher verwenden, umschließe sie in Anführungszeichen im YAML. Heredocs produzieren gültig aussehende, aber subtil kaputte Regeln. Zum Wahnsinnigwerden.

Das Muster über alle sieben: Der Fehlermodus ist Stille. Kein Crash, kein Stack Trace. Dinge funktionieren einfach nicht, und die Logs sagen, alles ist in Ordnung.

2 Stunden, 3 Peers, 2ms.

Die finale Architektur: Management-Server auf einem Contabo VPS (Ubuntu 24.04, 8GB RAM). Ein kombinierter netbird-server-Container, der Management, Signal, Relay und STUN laufen lässt. Separate Container für netbird-dashboard und netbird-coturn. Alles hinter der bestehenden Traefik-Instanz außer Coturn.

Drei Peers im Mesh: der Contabo VPS (Linux), ein Hostinger VPS (Linux) und mein MacBook (arm64). Ping zwischen den beiden VPS-Nodes: ~2ms P2P. Das ist direktes WireGuard, kein Relay-Hop.

Als ich das erste Mal diesen Ping laufen ließ und die Zahl zurückkommen sah, saß ich einfach eine Sekunde da. Zwei Millisekunden über zwei Rechenzentren in einem Netzwerk, das ich selbst gebaut habe. Kein Drittanbieter-Relay, kein Koordinationsserver in jemand anderes Cloud. Nur meine Boxen, die miteinander reden.

Ich hätte fast jemandem eine SMS darüber geschrieben. Dann erinnerte ich mich, dass normale Leute nicht wegen Ping-Zeiten aufgeregt werden.

Der macOS-Client installiert sich über Homebrew. Verbindet sich sauber nach dem Sleep wieder. Der iOS-Client ist ein nativer App Store-Download, funktioniert auf 4G/5G mit NAT-Traversal durch Coturn, wenn direktes P2P nicht möglich ist.

Authentifizierung läuft über eingebettetes Dex mit lokalen Usern. Kein externer Identity Provider, kein Okta, kein Auth0. Für ein Ein-Personen- (oder Drei-Personen-) Setup sind lokale User alles, was du brauchst.

Die Migration von Tailscale war der einfachste Teil. Tailscale-Client deinstallieren, nichts bricht auf der Service-Seite (deine Apps wissen nicht, welches VPN darunter läuft). SSH-Configs updaten, um auf die neuen Mesh-IPs zu zeigen. Fertig.

Derselbe VPS betreibt bereits andere selbst gehostete Services hinter demselben Traefik-Proxy. Selbes Muster, selber Stack, selbe Philosophie: Wenn es kritisch für deinen Workflow ist, besitze es.

Zwei Stunden insgesamt. Neunzig Minuten davon für den Dashboard-Authentifizierungs-Zirkus.

Wenn der Management-Server stirbt, sterben die Tunnel nicht.

Das ist der Teil, der die ganze Migration wert macht.

Wenn mein Management-Server ausfällt, laufen die bestehenden P2P-Tunnel weiter. WireGuard-Sessions zwischen Peers, die sich bereits kennen, überleben. Keine neuen Peers können beitreten, keine Config-Änderungen propagieren, aber Produktions-Traffic zwischen verbundenen Maschinen läuft ununterbrochen weiter. Das ist eine Eigenschaft von WireGuard, kein NetBird-Feature. Aber es ist eine Eigenschaft, die du nur bekommst, wenn die Koordinationsebene neben deinen anderen Services läuft, nicht in jemand anderes Cloud.

Das Backup-Verfahren ist kurz: Config-Dateien und Docker-Volumes auf den zweiten VPS repliziert. Recovery sind fünf Schritte. Docker installieren, Config kopieren, Volume wiederherstellen, DNS auf den Backup-Server zeigen lassen, docker compose up. Clients wieder verbinden. Ich hab's getestet. Es funktioniert.

Ich habe auch die Management-Domain zu etwas weniger Offensichtlichem verschoben. Security through Obscurity ist keine Strategie, aber es gibt keinen Grund, deinen Koordinations-Endpunkt leicht auffindbar zu machen.

Die Industrie wird dir weiter "Zero Config" und "It just works" verkaufen. Und sie haben recht, es funktioniert. Bis der Anbieter die Preise ändert, einen Tarif killt oder ausfällt. Dann findest du heraus, dass dein privates Netzwerk von einem Server abhing, den du nie besessen hast.

Das Mesh-VPN ist nicht der komplizierte Teil. Es sind 2 Minuten und 2ms. Der komplizierte Teil ist, es in einen Stack zu verdrahten, der bereits läuft. Aber wenn es einmal fertig ist, gehört es dir. Management-Server stirbt, Tunnel überleben. Du willst migrieren, du migrierst.

Deine Infra zu besitzen bedeutet, frei und sicher zu sein. 🤷

Quellen

(*) Das Cover ist KI-generiert. Die WireGuard-Tunnel sind jedoch sehr real und routen gerade Pakete, während wir sprechen.

Dieser Artikel enthält Affiliate-Links. Ich könnte eine kleine Provision verdienen, wenn du über sie kaufst.