Tailscale VPN: eigene Services auf eigener Infrastruktur verbinden

Tailscale VPN: eigene Services auf eigener Infrastruktur verbinden

Proxmox im Rechenzentrum, ein Laptop im Home Office, ein Raspberry Pi am Feldrand und eine DGX Spark für Inferenz: eigene Hardware ist selten an einem Ort. NAT, Firewalls und dynamische IPs trennen die Geräte. Manuelles WireGuard bedeutet: Keys tauschen, IPs pflegen, Firewall-Regeln nachziehen.

Tailscale baut auf WireGuard auf und macht daraus ein Minuten-Setup. Wir nutzen das Tailscale-Protokoll mit einem wichtigen Unterschied: wir hosten die Control Plane selbst. Headscale ist das Open-Source-Drop-in-Replacement dafür.

Ergebnis: Proxmox-Hosts, externe Laptops, IoT-Geräte wie ein Solar-Lade-Controller, Raspberry-Pi-Edge-Nodes und die DGX Spark Node hängen im gleichen privaten Netz. Lokale KI lässt sich direkt in Web-Anwendungen nutzen – ohne Ports ins Internet zu öffnen.

Das Problem: eigene Infrastruktur, verteilte Netze

Wenn du eigene Hardware betreibst, kennst du das:

  • Ein Proxmox-Host im Rechenzentrum.
  • Ein GitLab Runner auf einer VM.
  • Eine DGX Spark Node für Inferenz.
  • Ein Raspberry Pi irgendwo draußen, der einen Solar-Lade-Controller ausliest.
  • Dein Laptop aus dem Home Office oder von unterwegs.

Die Maschinen stehen hinter einem NAT, haben dynamische IPs oder sitzen in fremden Netzwerken. Du willst, dass sie miteinander reden, als wären sie im selben LAN. Ohne Tailscale heißt das: Keys tauschen, IPs verteilen, Firewall-Regeln pflegen. Bei jeder neuen Maschine fängt das Spiel von vorne an.

Tailscale im Überblick

Tailscale nimmt WireGuard und ergänzt die Koordination: Keys, IPs, DNS, NAT-Traversal. Der Client auf jedem Host verbindet sich mit einer zentralen Control Plane. Die echten Daten fließen Peer-to-Peer – verschlüsselt, ohne Umweg über externe Server.

Das Protokoll funktioniert. Die zentrale Control Plane wollten wir aber selbst betreiben.

Headscale: eigener Control-Server

Headscale ist ein Open-Source-Projekt, das die Tailscale-Control-Plane-API implementiert. Wir hosten es als Docker-Container. Die Clients verwenden die offiziellen Tailscale-Binaries, registrieren sich aber bei unserem eigenen Server.

Alle Kommandos, die man aus der Tailscale-Dokumentation kennt – tailscale uptailscale statustailscale sshtailscale serve – funktionieren unverändert. Der einzige Unterschied ist die --login-server-Option.

Registrierung eines Hosts:

tailscale up --login-server=https://<headscale-server> --accept-routes=true
tailscale status

Ausgabe in etwa:

100.64.0.1  host2           user@ linux   -
100.64.0.2  proxmox-01      user@ linux   -
100.64.0.3  dgx-spark      user@ linux   -
100.64.0.4  edge-solar-01  user@ linux   -
100.64.0.5  laptop-dev-01   user@ darwin  -

Jeder Host bekommt eine stabile IP im 100.64.0.0/10-Bereich. MagicDNS liefert dazu echte FQDNs wie dgx-spark.<user>.<tailnet> – nicht nur Kurznamen. Für unsere Services fühlt sich das wie ein internes Netz an, egal wo die Maschinen stehen. In Konfigurationen und Zertifikaten arbeiten wir mit Namen statt IPs.

Was wir verbunden haben

GerätRolleStandortTailscale-Name
proxmox-01Headscale Control Plane, Docker, TraefikRZproxmox-01
proxmox-02Virtualisierung, GitLab Runner, VMsRZproxmox-02
dgx-sparkLLM-Inferenz, LiteLLM-ProxyHome-Labdgx-spark
edge-solar-01IoT-Gateway: Solar-Lade-Controller, MonitoringEdge / Feldedge-solar-01
laptop-dev-01Entwicklung, AdminHome Office / mobillaptop-dev-01
laptop-dev-02EntwicklungHome Office / mobillaptop-dev-02

Die Hosts sprechen über Tailscale-IPs. Container auf den Hosts nutzen das Host-Interface, ohne selbst Tailscale installiert zu haben.

Konkretes Beispiel: Review Bot, LiteLLM und DGX Spark

Unser GitLab Review Bot fragt ein Sprachmodell nach Review-Kommentaren. Früher hätte das gegen eine Cloud-API laufen können. Stattdessen schickt er den Request an einen LiteLLM-Proxy, der auf der DGX Spark Node läuft:

http://dgx-spark:4000/v1/chat/completions

Der Bot selbst läuft auf dem Proxmox-Host. Der LiteLLM-Proxy leitet die Anfrage an das lokale Modell auf der DGX Spark weiter. Alles passiert im 100.x.x.x-Netz. Kein öffentlicher Port, keine Cloud-Abhängigkeit.

Wie genau wir den Review Bot, LiteLLM und die DGX Spark Node zusammengebaut haben, beschreibe ich im nächsten Artikel.

Lokale KI in Web-Anwendungen

Dasselbe Muster erlaubt, lokale Modelle in Web-basierte Anwendungen einzubinden. Eine Web-App hinter Traefik ruft keine Cloud-API auf, sondern den LiteLLM-Proxy im eigenen Netz:

http://dgx-spark.&lt;user>.&lt;tailnet>:4000/v1/chat/completions

Dank MagicDNS löst sich der Name im Tailscale-Netz auf. Für die Web-App fühlt sich das wie ein interner Service an. Für das Modell läuft die Inferenz auf der DGX Spark Node. Daten bleiben im eigenen Netz, Latenz bleibt niedrig, und externe Abhängigkeiten fehlen.

ACLs: Wer darf mit wem sprechen

Headscale übernimmt die Tailscale-ACL-Syntax. Wir definieren pro Tag oder pro Gruppe, wer welchen Host und Port erreichen darf.

{
  "acls": [
    {
      "action": "accept",
      "src": ["tag:review-bot"],
      "dst": ["tag:llm-proxy:4000"]
    },
    {
      "action": "accept",
      "src": ["group:developers"],
      "dst": ["tag:proxmox:22", "tag:edge-solar:80"]
    }
  ]
}

Der Review Bot kommt an den Proxy. Entwickler dürfen per SSH auf Proxmox zugreifen und die Statusseite des Solar-Pi abrufen. Ein Laptop ohne passendes Tag sieht die Ressource nicht.

Was selbst gehostet bedeutet – und was nicht

Mit Headscale bleiben Schlüssel und Registrierungsdaten in unserer Infrastruktur. Wir müssen Tailscale Inc. nicht vertrauen, dass sie die Control Plane korrekt betreibt. Wir müssen uns selbst darum kümmern.

Das bedeutet:

  • Eigene Backups der Headscale-Datenbank.
  • Eigene Updates und Wartung.
  • Eigene Verfügbarkeit der Control Plane. Bestehende Verbindungen halten bei einem Ausfall, neue Registrierungen gehen nicht.

Headscale ist kein vollständiger Ersatz für die Tailscale-SaaS-Lösung. Einige Features – etwa Tailscale Funnel – sind nicht verfügbar oder anders gelöst. Wer öffentliche Endpunkte braucht, setzt weiterhin einen Reverse Proxy wie Traefik mit Let’s Encrypt davor.

Wann es passt und wann nicht

Tailscale plus Headscale lohnt sich, wenn du:

  • eigene Hardware an vielen Standorten betreibst,
  • keine externe Cloud-Control-Plane willst,
  • zwischen zehn und einigen hundert Nodes vernetzen musst,
  • ACLs und Audit-Logs brauchst.

Es wird unhandlich, wenn du tausende anonyme Clients oder komplexe Multi-Region-Topologien mit eigenen Routing-Entscheidungen brauchst. Dann greifst du auf klassisches WireGuard oder IPsec zurück.

Fazit

Wir haben mit Tailscale ein Protokoll, das funktioniert, und mit Headscale eine Control Plane, die uns gehört. Das Ergebnis ist ein privates Netz, das Proxmox, Laptops, IoT-Geräte wie unser Solar-Lade-Controller, Edge-Pis und GPU-Workloads auf einer DGX Spark verbindet. Ohne Port-Forwarding, ohne öffentliche IPs für interne Services.

Wenn du heute noch WireGuard-Configs von Hand verteilst, lohnt sich der Blick auf Tailscale. Wenn dir die Cloud-Control-Plane nicht passt, ist Headscale der nächste Schritt.

Ein Review Bot auf einer DGX Spark ist nur ein Beispiel – mehr dazu im nächsten Artikel.


Setzt ihr Tailscale oder Headscale ein? Was verbindet ihr damit – und wo sind für euch Grenzen?

Philipp Haußleiter

Version 4.5. Ich arbeite seit etwa 17 Jahren als IT-Berater und Software Engineer. Meine Karriere begann mit vielfältigen Projekten – von iOS-Entwicklung über Microsoft BI Tooling bis hin zum Aufbau größerer Hadoop-Cluster. Heute liegt mein Schwerpunkt auf Software-Architektur, Systemdesign und der Entwicklung robuster, nachhaltiger IT-Lösungen. Dabei verfolge ich konsequent einen First-Principles-Ansatz: Ich hinterfrage bestehende Annahmen und bilde mir durch eigenes Ausprobieren eine fundierte, kritische Meinung zu neuen Technologien – auch zu KI –, um echten Mehrwert von Hype zu unterscheiden. Seit 2003 betreibe ich eigene Server, um einen Ausgleich zum Beratungsgeschäft zu finden und praktische Erfahrungen zu sammeln.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert