Zum Inhalt

RFC-002: VPN-Redesign — Multi-Site Headscale mit ACL-Isolation

Feld Wert
Status draft
Datum 2026-03-22
Betrifft homelab-external, homeserver, novabrands-mgmt, claude-pi
Tracking-Issues noch keine
Verwandt RFC-003 (Authelia/LDAP, geplant), RFC-004 (VLANs, geplant)

Problem

Das aktuelle Headscale-VPN ist auf eine Person (Robin) und einen Standort (Homelab) ausgelegt. Es gibt einen einzigen User-Namespace (homelab), eine pauschale autogroup:member -> *:* Regel und keine Isolation zwischen Teilnehmern.

Folgende Anforderungen koennen damit nicht abgebildet werden:

  1. Multi-Site: Novabrands (OVH Frankfurt) und Thies' HomeSite sollen ins VPN
  2. Multi-User: Robin und Thies brauchen unterschiedliche Zugriffsrechte
  3. ACL-Isolation: Jeder sieht nur seine eigene HomeSite + gemeinsame Ressourcen
  4. Monitoring: Hetzner-Server darf nur Health-Endpoints erreichen, nicht alles
  5. Exit-Node-Tracking: Traffic-Metriken pro Geraet fehlen
  6. DERP-Redundanz: Ein einziger DERP-Server ist ein Single Point of Failure
  7. VLAN-Vorbereitung: Zukuenftige VLAN-Segmentierung muss mit dem VPN kompatibel sein

Vorschlag

Komplette Ueberarbeitung der Headscale-Konfiguration: User-Struktur, ACL-Policy, Routing, DERP-Infrastruktur und Exit-Node-Architektur. Die Umsetzung erfolgt in vier Phasen.

Explizit nicht in Scope

  • Authelia/LDAP/OIDC — Zentrales Identity-Management kommt in RFC-003. Headscale unterstuetzt OIDC nativ; Authelia auf dem Hetzner-Server als Provider ist die geplante Richtung (VPN-Login + SSO fuer Web-Services).
  • VLAN-Segmentierung — Konkrete VLAN-Planung kommt in RFC-004. Dieser RFC stellt sicher, dass das VPN-Design VLAN-kompatibel ist.

Ist-Zustand

Headscale-Konfiguration

Parameter Wert
Server Hetzner CX23 (Falkenstein)
Version Headscale v0.28.0, Headplane v0.6.2
User-Namespace homelab (einziger)
IPv4-Praefix 100.64.0.0/10
IPv6-Praefix fd7a:115c:a1e0::/48
DERP Eingebetteter DERP (Region homelab, ID 999)
DNS MagicDNS, Base-Domain tailnet, NS: Pi-hole

Aktuelle ACL-Policy

Regel Quelle Ziel
Vollzugriff autogroup:member *:*
Internet (Exit Node) autogroup:member autogroup:internet:*
Monitoring tag:server homelab-network:53,80,443,3000,8080,8123,9090,9100
ICMP * *:*
SSH autogroup:member autogroup:member, autogroup:tagged

Probleme mit dem Ist-Zustand:

  • autogroup:member -> *:* ist ein Catch-All ohne Isolation
  • Monitoring-Regel erlaubt Ports, die Uptime Kuma wahrscheinlich nicht braucht (Port 53/DNS, 3000/Grafana, 8123/Home Assistant, 9090/Prometheus)
  • Nur ein User-Namespace — kein Multi-User moeglich
  • Novabrands ist komplett isoliert (kein VPN)
  • Exit Node laeuft auf dem NUC, Traffic nicht separat messbar

Aktuelle Nodes

Node Standort Rolle User
NUC Homelab Subnet Router + Exit Node homelab
Claude-Pi Homelab Dev-Workstation homelab
Hetzner Falkenstein Coordination + Monitoring homelab

Soll-Zustand

Neue User-Struktur

Migration von einem einzelnen Namespace auf zwei personenbezogene Users. Server werden ueber Tags klassifiziert (Hybrid-Ansatz).

User Zweck Geraete (Beispiele)
robin Robins persoenliche Geraete Handy, Laptop, Tablet, Claude-Pi
thies Thies' persoenliche Geraete Handy, Laptop

Migration: Der bestehende User homelab wird zu robin umbenannt. Alle existierenden Nodes bleiben erhalten.

Tag-Struktur

Tag Zweck Nodes
tag:homelab Homeserver-Infrastruktur (NUC) NUC Tailscale-Client
tag:novabrands Novabrands OVH-Server Novabrands Tailscale-Client
tag:thies-home Thies' HomeSite-Server Thies' Server Tailscale-Client
tag:hetzner Hetzner Monitoring/Infra Hetzner Tailscale-Client
tag:gateway Subnet Router Nodes NUC + dedizierter Exit-Node-Server
tag:exit-node Exit Node Dedizierter Server im Homelab

Tag-Ownership:

"tagOwners": {
  "tag:homelab":    ["robin"],
  "tag:novabrands": ["robin", "thies"],
  "tag:thies-home": ["thies"],
  "tag:hetzner":    ["robin"],
  "tag:gateway":    ["robin"],
  "tag:exit-node":  ["robin"]
}

ACL-Policy (vollstaendig, Policy v2, HuJSON-Format)

Gruppen:

"groups": {
  "group:novabrands-team": ["robin", "thies"]
}

Zugriffsregeln:

# Quelle Ziel Ports Beschreibung
1 robin tag:homelab * Robin: Vollzugriff auf Homelab
2 robin robin * Robin: Zugriff auf eigene Geraete
3 thies tag:thies-home * Thies: Vollzugriff auf seine HomeSite
4 thies thies * Thies: Zugriff auf eigene Geraete
5 group:novabrands-team tag:novabrands 22,80,443 Team: SSH + Web auf Novabrands
6 group:novabrands-team tag:hetzner 80,443 Team: Web-Zugriff auf Monitoring
7 tag:hetzner tag:homelab 53,80,443 (+ auditierte Ports) Monitoring: Health-Checks + DNS Homelab
8 tag:hetzner tag:novabrands 80,443 Monitoring: Health-Checks Novabrands
9 tag:hetzner tag:thies-home 80,443 Monitoring: Health-Checks Thies
10 robin autogroup:internet * Robin: Exit-Node-Nutzung
11 * * ICMP Ping fuer Diagnose

Aktionspunkt: Monitoring-Ports auditieren

Regel 7 enthaelt Port 53 (DNS), da Uptime Kuma Pi-hole als DNS-Resolver nutzt und DNS-Monitoring-Checks konfiguriert sind. Die weiteren Ports (80,443 + eventuelle Service-spezifische Ports) muessen anhand der Uptime-Kuma-Konfiguration auditiert werden. Ports die nicht aktiv gebraucht werden, werden entfernt. Die ICMP-Catch-All-Regel (Regel 11) deckt Ping-Monitoring auf allen Sites ab.

Tailscale SSH:

"ssh": [
  {
    "action": "accept",
    "src": ["robin"],
    "dst": ["robin", "tag:homelab", "tag:novabrands", "tag:hetzner"],
    "users": ["autogroup:nonroot"]
  },
  {
    "action": "accept",
    "src": ["thies"],
    "dst": ["thies", "tag:thies-home", "tag:novabrands"],
    "users": ["autogroup:nonroot"]
  }
]

AutoApprovers:

"autoApprovers": {
  "routes": {
    "10.10.10.0/24": ["tag:gateway"],
    "0.0.0.0/0":     ["tag:exit-node"],
    "::/0":           ["tag:exit-node"]
  }
}

Design-Entscheidungen:

  • Die autogroup:member -> *:* Catch-All-Regel entfaellt komplett
  • Thies hat keinen Exit-Node-Zugriff (erweiterbar bei Bedarf)
  • Robin hat bewusst keinen Zugriff auf tag:thies-home (Isolation). Bei Bedarf fuer Debugging kann temporaer eine Regel ergaenzt werden.
  • Novabrands erlaubt SSH (Port 22) + Web (80/443) — kein direkter DB-Zugriff
  • Monitoring ist auf Health-Checks + DNS beschraenkt, kein Prometheus/Node-Exporter-Scraping
  • Regel 6 (group:novabrands-team -> tag:hetzner:80,443) gibt Thies Zugriff auf Uptime Kuma und Headplane. Headplane erfordert zusaetzlich einen API-Key fuer Aenderungen — reiner Lesezugriff ist akzeptabel. Bei Bedenken kann Headplane zusaetzlich ueber Basic-Auth oder IP-Whitelist abgesichert werden.
  • MagicDNS: Alle Nodes im Tailnet koennen einander ueber MagicDNS aufloesen (<hostname>.tailnet). Die ACLs verhindern trotzdem den tatsaechlichen Zugriff — DNS-Aufloesung allein ist kein Sicherheitsrisiko.
  • Skalierung: Neue Person = neuer User + Gruppe erweitern. Neue Site = neuer Tag.

Netzwerk-Topologie

                    ┌─────────────────────┐
                    │  Hetzner CX23       │
                    │  tag:hetzner        │
                    │  ─────────────────  │
                    │  Headscale (coord)  │
                    │  DERP #1 (ID 999)   │
                    │  Uptime Kuma        │
                    │  Tailscale-Client   │
                    └────────┬────────────┘
            ┌────────────────┼────────────────┐
            │                │                │
   ┌────────┴──────┐  ┌─────┴──────┐  ┌──────┴────────┐
   │ Robin Homelab  │  │ Novabrands │  │ Thies HomeSite│
   │ 10.10.10.0/24  │  │ OVH FRA    │  │ (eigenes Netz)│
   │ tag:homelab    │  │ tag:novabr. │  │ tag:thies-home│
   │ ────────────── │  │ ─────────  │  │ ──────────── │
   │ NUC (gateway)  │  │ TS-Client  │  │ TS-Client    │
   │ Exit-Node-Srv  │  │ DERP #2    │  │              │
   │ (exit-node)    │  │ (ID 1000)  │  │              │
   └────────────────┘  └────────────┘  └──────────────┘
   ┌────────┴──────┐
   │ Claude-Pi     │
   │ (User robin)  │
   └───────────────┘

Routing

Node Advertisiert Tags Funktion
NUC (Homelab) 10.10.10.0/24 tag:homelab, tag:gateway Subnet Router
Dedizierter Server 10.10.10.0/24, 0.0.0.0/0, ::/0 tag:gateway, tag:exit-node Subnet Router + Exit Node
Novabrands (OVH) — (nur Client) tag:novabrands Tailscale-Client, DERP #2
Hetzner — (nur Client) tag:hetzner Coordination, DERP #1
Thies' Server — (nur Client, spaeter evtl. Subnet¹) tag:thies-home Tailscale-Client
Claude-Pi — (User robin) Dev-Workstation

Die Redundanz zweier Subnet Router (NUC + dedizierter Server) fuer 10.10.10.0/24 sorgt dafuer, dass das Homelab-Subnetz erreichbar bleibt, auch wenn ein Node ausfaellt. Tailscale waehlt automatisch den guenstigsten Pfad.

¹ Falls Thies' Server spaeter als Subnet Router fungiert, muss autoApprovers um sein Subnetz erweitert werden (z.B. "10.20.10.0/24": ["tag:thies-home"]).

DERP-Konfiguration

Region ID Server Standort
homelab 999 headscale.homelab-external.robinwerner.net Falkenstein (Hetzner)
novabrands 1000 derp.novabrands.org Frankfurt (OVH)
Tailscale auto Offizielle Tailscale DERP-Map Global (Fallback)

Der zweite DERP-Server auf Novabrands bietet Redundanz und kuerzere Relay-Wege fuer Verbindungen zwischen OVH und anderen Nodes. Er wird als Standalone-derper-Container auf dem Novabrands-Server betrieben (nicht als eingebetteter DERP im Headscale-Server, da Headscale nur auf Hetzner laeuft). Der derper-Container erhaelt eine eigene Subdomain (derp.novabrands.org) mit TLS via Traefik (Let's Encrypt, konsistent mit dem restlichen Stack). Die DERP-Map in der Headscale-Konfiguration wird um die Region novabrands (ID 1000) erweitert.

Exit-Node Traffic-Metriken

Der dedizierte Exit-Node-Server exportiert Tailscale-Metriken fuer Prometheus:

  1. Tailscale Debug Metrics: Der Tailscale-Daemon bietet unter --debug=<addr> einen Metrics-Endpoint mit Bytes in/out pro Peer
  2. Node-Exporter: Netzwerk-Interface-Metriken des tailscale0-Interfaces (Gesamtdurchsatz)
  3. Grafana-Dashboard: Neues Dashboard "VPN Traffic" mit Aufschluesselung pro Geraet und Zeitverlauf

Prometheus scrapt den Exit-Node-Server ueber das Tailnet (kein externer Zugriff noetig).

VLAN-Kompatibilitaet

Dieser Abschnitt beschreibt, wie Tailscale mit einer zukuenftigen VLAN-Segmentierung des Heimnetzes interagiert. Die konkrete VLAN-Planung erfolgt in RFC-004.

Wie Tailscale mit VLANs funktioniert:

  1. Subnet Router mit VLAN-Trunking: Der Tailscale-Subnet-Router (NUC oder dedizierter Server) bekommt ein Trunk-Interface via UniFi und ist in allen relevanten VLANs Mitglied. Er advertisiert mehrere Subnetze (z.B. 10.10.10.0/24, 10.10.20.0/24, 10.10.30.0/24).

  2. ACL-Steuerung pro VLAN: Headscale-ACLs koennen auf Subnetz-Ebene einschraenken, wer in welches VLAN darf:

    // Robin darf ins Server-VLAN und IoT-VLAN
    { "src": ["robin"], "dst": ["10.10.10.0/24:*", "10.10.20.0/24:*"] }
    // Thies hat keine Regel fuer Homelab-Subnetze = kein Zugriff
    

  3. DNS: Pi-hole muss aus allen VLANs erreichbar bleiben. MagicDNS funktioniert innerhalb des Tailnet unabhaengig von VLANs.

  4. Empfehlung: Ein Subnet Router mit Trunk-Interface ist fuer ein Homelab ausreichend. Pro-VLAN Subnet Router waere ueberdimensioniert.

Betroffene Repos

Repo Aenderung
homelab-external ACL-Policy neu schreiben, User-Migration, DERP-Config anpassen
homeserver Exit-Node-Funktion vom NUC entfernen, Tailscale-Config anpassen
novabrands-mgmt Tailscale-Client + DERP-Server hinzufuegen
homelab-documentation Dokumentation aktualisieren (VPN-Topologie, LikeC4-Modell)

Umsetzungsphasen

Phase 1: ACL-Cleanup und User-Migration

  1. Backup: Headscale-Datenbank sichern (pg_dump) und aktuelle acl.json archivieren
  2. Headscale-User umbenennen: docker exec headscale headscale users rename homelab robin (unterstuetzt seit Headscale v0.23; Node-Zuordnungen bleiben erhalten)
  3. Bestehenden tag:server durch tag:hetzner ersetzen, zusaetzlich tag:homelab und tag:gateway auf dem NUC setzen
  4. Neue ACL-Policy deployen (nur bestehende Infra, keine neuen Sites)
  5. Uptime-Kuma-Checks auditieren und Monitoring-Ports in ACL anpassen
  6. Testen: Robin hat weiterhin vollen Zugriff, Monitoring funktioniert
  7. Rollback: Bei Problemen acl.json und DB-Dump wiederherstellen, User zurueck auf homelab umbenennen

Phase 2: Novabrands-Anbindung

  1. Tailscale-Client auf Novabrands-Server installieren
  2. Node mit tag:novabrands taggen
  3. DERP #2 (ID 1000) auf Novabrands konfigurieren (derp.novabrands.org)
  4. ACL-Regeln fuer group:novabrands-team -> tag:novabrands aktivieren
  5. Testen: Robin erreicht Novabrands Web-Services und SSH ueber VPN

Phase 3: Thies-Integration

  1. Headscale-User thies anlegen
  2. Pre-Auth-Key fuer Thies generieren (reusable, 90 Tage Laufzeit). Fuer Server-Nodes empfohlen: separater Key mit --tags tag:thies-home. Bis RFC-003 (Authelia/OIDC) umgesetzt ist, bei Ablauf manuell erneuern.
  3. Tailscale-Client auf Thies' Server installieren, Node mit tag:thies-home taggen
  4. ACL-Regeln fuer Thies aktivieren
  5. Testen: Thies erreicht nur seine HomeSite + Novabrands, nicht Robins Homelab

Phase 4: Exit-Node-Migration

  1. Dedizierten Server im Homelab aufsetzen (OS, Docker, Tailscale)
  2. Tags setzen: tag:gateway, tag:exit-node
  3. Subnetze advertisieren: 10.10.10.0/24, 0.0.0.0/0, ::/0
  4. Exit-Node-Funktion vom NUC entfernen (NUC bleibt Subnet Router)
  5. Traffic-Metriken konfigurieren (Tailscale debug metrics -> Prometheus)
  6. Grafana-Dashboard "VPN Traffic" erstellen
  7. Testen: Exit-Node funktioniert, Traffic-Metriken sichtbar in Grafana

Offene Aktionspunkte

  • Uptime-Kuma-Checks auditieren: exakte Port-Liste fuer Monitoring-ACL ermitteln
  • Hardware fuer dedizierten Exit-Node-Server auswaehlen
  • DNS-Eintrag derp.novabrands.org anlegen + TLS-Zertifikat
  • Thies informieren und Tailscale-Installation koordinieren
  • Nach Abschluss: LikeC4-Modell und Dokumentationsseiten aktualisieren

Risiken

Risiko Mitigation
User-Umbenennung bricht bestehende Node-Zuordnungen headscale users rename ist seit v0.23 stabil; DB-Backup vor Migration, Rollback-Plan in Phase 1
ACL-Lockout bei fehlerhafter Policy Neue ACL zuerst lokal validieren (headscale policy validate), Rollback-Plan bereithalten
DERP #2 auf Novabrands nicht erreichbar (Firewall) Port 3478 (STUN) und 443 (HTTPS/DERP) in OVH-Firewall freigeben
Thies' Netzwerk blockiert Tailscale-Traffic DERP als Fallback reicht aus, direkter WireGuard-Tunnel ist optional
Redundante Subnet Router verursachen Routing-Konflikte Tailscale waehlt automatisch den besten Pfad, testen mit tailscale status

Zukunftsaussichten

  • RFC-003 (Authelia/LDAP): Headscale OIDC-Integration mit Authelia als Provider auf dem Hetzner-Server. Ersetzt Pre-Auth-Keys durch Login mit MFA. Authelia gleichzeitig als Forward-Auth fuer Web-Services (SSO).
  • RFC-004 (VLANs): Segmentierung des Heimnetzes (Server, IoT, Management, Gaeste). Subnet Router advertisiert alle VLANs, ACLs steuern Zugriff pro VLAN.
  • Skalierung: 1-2 weitere Personen und Kundeninfrastruktur sind mittelfristig denkbar. Das Hybrid-Modell (Users + Tags + Groups) skaliert dafuer ausreichend.