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:
- Multi-Site: Novabrands (OVH Frankfurt) und Thies' HomeSite sollen ins VPN
- Multi-User: Robin und Thies brauchen unterschiedliche Zugriffsrechte
- ACL-Isolation: Jeder sieht nur seine eigene HomeSite + gemeinsame Ressourcen
- Monitoring: Hetzner-Server darf nur Health-Endpoints erreichen, nicht alles
- Exit-Node-Tracking: Traffic-Metriken pro Geraet fehlen
- DERP-Redundanz: Ein einziger DERP-Server ist ein Single Point of Failure
- 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:
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:
- Tailscale Debug Metrics: Der Tailscale-Daemon bietet unter
--debug=<addr>einen Metrics-Endpoint mit Bytes in/out pro Peer - Node-Exporter: Netzwerk-Interface-Metriken des
tailscale0-Interfaces (Gesamtdurchsatz) - 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:
-
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). -
ACL-Steuerung pro VLAN: Headscale-ACLs koennen auf Subnetz-Ebene einschraenken, wer in welches VLAN darf:
-
DNS: Pi-hole muss aus allen VLANs erreichbar bleiben. MagicDNS funktioniert innerhalb des Tailnet unabhaengig von VLANs.
-
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¶
- Backup: Headscale-Datenbank sichern (
pg_dump) und aktuelleacl.jsonarchivieren - Headscale-User umbenennen:
docker exec headscale headscale users rename homelab robin(unterstuetzt seit Headscale v0.23; Node-Zuordnungen bleiben erhalten) - Bestehenden
tag:serverdurchtag:hetznerersetzen, zusaetzlichtag:homelabundtag:gatewayauf dem NUC setzen - Neue ACL-Policy deployen (nur bestehende Infra, keine neuen Sites)
- Uptime-Kuma-Checks auditieren und Monitoring-Ports in ACL anpassen
- Testen: Robin hat weiterhin vollen Zugriff, Monitoring funktioniert
- Rollback: Bei Problemen
acl.jsonund DB-Dump wiederherstellen, User zurueck aufhomelabumbenennen
Phase 2: Novabrands-Anbindung¶
- Tailscale-Client auf Novabrands-Server installieren
- Node mit
tag:novabrandstaggen - DERP #2 (ID 1000) auf Novabrands konfigurieren (
derp.novabrands.org) - ACL-Regeln fuer
group:novabrands-team -> tag:novabrandsaktivieren - Testen: Robin erreicht Novabrands Web-Services und SSH ueber VPN
Phase 3: Thies-Integration¶
- Headscale-User
thiesanlegen - 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. - Tailscale-Client auf Thies' Server installieren, Node mit
tag:thies-hometaggen - ACL-Regeln fuer Thies aktivieren
- Testen: Thies erreicht nur seine HomeSite + Novabrands, nicht Robins Homelab
Phase 4: Exit-Node-Migration¶
- Dedizierten Server im Homelab aufsetzen (OS, Docker, Tailscale)
- Tags setzen:
tag:gateway,tag:exit-node - Subnetze advertisieren:
10.10.10.0/24,0.0.0.0/0,::/0 - Exit-Node-Funktion vom NUC entfernen (NUC bleibt Subnet Router)
- Traffic-Metriken konfigurieren (Tailscale debug metrics -> Prometheus)
- Grafana-Dashboard "VPN Traffic" erstellen
- 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.organlegen + 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.