· Henning Scholand · Projekte · 18 Min. Lesezeit
MPLS war zu teuer — Headscale, MikroTik und echtes Zero Trust
Ich betreibe vier Standorte über Headscale und MikroTik — eigenes Homelab, produktiv seit einem Jahr. Dieselbe Architektur hat einem Kunden geholfen, Telekom-MPLS für €2.400 pro Monat loszuwerden.

Ich betreibe vier Standorte über ein WireGuard-Mesh mit Headscale als selbst-gehostetem Control Plane und MikroTik für BGP-Routing. Produktiv seit gut einem Jahr — kein Lab-Spielzeug, echte Infrastruktur.
Das Setup ist gleichzeitig der Proof-of-Concept für ein Kundenprojekt: ein mittelständisches Unternehmen, drei Standorte, alle über MPLS der Deutschen Telekom verbunden. Monatliche Kosten: €2.400. Vertragslaufzeit: 24 Monate. Änderungswunsch (neuer Standort dazunehmen): Vorlaufzeit 3–6 Monate, einmalige Installationskosten €800.
Dieser Artikel beschreibt die Architektur meines Homelabs — und warum sie sich direkt als MPLS-Ablösung skalieren lässt.
Hinweis: Alle IPs, Hostnamen und Sicherheitskonfigurationen in den Code-Beispielen sind angepasst. Die gezeigten Werte (Subnetz-Adressen, AS-Nummern, Endpunkte) entsprechen nicht dem produktiven Setup.
Warum MPLS zu teuer ist
MPLS (Multiprotocol Label Switching) ist eine Technik für dedizierte WAN-Verbindungen zwischen Unternehmensstandorten. Der Carrier baut virtuelle Leitungen zwischen Standorten auf, garantiert Bandbreite und Latenzen und liefert das als Managed Service.
Was man dafür bezahlt:
| Kostenpunkt | Typischer Wert |
|---|---|
| Monatliche Leitungsmiete pro Standort | €500–1.500 |
| Einmalige Installation pro Standort | €500–1.500 |
| Mindestvertragslaufzeit | 24 Monate |
| Änderungskosten (neuer Standort) | €800–2.000 + Vorlaufzeit |
| SLA-Upgrade auf 4h-Entstörung | Aufpreis €200–500/Monat |
Was man bekommt: Garantierte Bandbreite, SLA mit Entstörzeit, Layer-3-Konnektivität zwischen Standorten, kein Internetzugang-Routing nötig, alles managed vom Carrier.
Was man nicht bekommt: Flexibilität. Ein neuer Mitarbeiter im Homeoffice? Nicht im MPLS-Netz. Ein temporärer Standort für ein Projekt? Zwei bis vier Monate Vorlaufzeit. Standort fällt weg? Vertragsstrafe bis zum Laufzeitende.
Was sich verändert hat: Glasfaser-Ausbau hat Internet-Bandbreiten explodieren lassen. Symmetrische 1-GBit/s-Leitungen für €100–150/Monat sind heute keine Seltenheit. Die Prämisse hinter MPLS — Internet ist unzuverlässig und langsam — gilt für moderne Glasfaser-Anschlüsse nicht mehr.
Die Rechnung für den Kunden, der MPLS ablösen will:
MPLS (3 Standorte × €800/Monat) × 24 Monate = 57.600 €
Headscale (Hetzner Dedicated Server, ~€60/Monat) = 1.440 €
Differenz über 2 Jahre ≈ 56.160 €Das ist keine exotische Optimierung. Das ist ein offensichtlicher Business Case.
Zero Trust — was das für Netzwerke bedeutet
“Zero Trust” ist ein Konzept, kein Produkt. Der Kern: kein System, kein Nutzer, kein Gerät bekommt implizites Vertrauen durch seine Netzwerklage. Wer im internen LAN ist, ist nicht automatisch vertrauenswürdig.
Das klingt selbstverständlich. In der Praxis bedeutet klassisches Netzwerk-Design das Gegenteil: eine Firewall am Perimeter, innen alles flat. Wer es ins interne Netz schafft — ob durch VPN, gestohlene Credentials oder kompromittierten Rechner — kann sich oft frei bewegen. MPLS macht das Ganze noch großzügiger: alle Standorte liegen im selben implizit vertrauenswürdigen Layer-3-Netz.
Zero Trust Network Access (ZTNA) ersetzt den Perimeter durch:
- Identity: Wer bist du? Nicht: bist du im richtigen Netz?
- Device Posture: Ist das Gerät known und compliant?
- Least Privilege Access: Jeder bekommt nur Zugriff auf das, was er braucht — nicht auf das ganze Netz
- Mikrosegmentierung: Workloads kommunizieren nur mit explizit erlaubten Zielen
Der Widerspruch: Site-to-Site klingt nach klassischem VPN
Hier ist die berechtigte Frage: Subnet Router advertisen ein ganzes /24 ins Tailnet. MikroTik propagiert Routen zwischen Standorten via BGP. Ist das nicht genau das, was Zero Trust ablösen soll — ein flaches Netz, in dem alle Standorte füreinander erreichbar sind?
Zum Teil ja. Der Unterschied liegt im Kontrollmechanismus.
Bei einem klassischen Site-to-Site-VPN-Tunnel besteht implizites Vertrauen zwischen den Netzwerken: wer im Tunnel ist, darf. Die Zugriffskontrolle hängt an Firewall-Regeln am Perimeter — und endet dort.
Bei Headscale mit Subnet Routern ist jeder Subnet Router ein individuell authentifizierter Node mit eigenem WireGuard-Schlüsselpaar. Die ACL-Policy greift auf Overlay-Ebene und definiert, welcher Node mit welchem Ziel-Prefix und welchem Port kommunizieren darf — unabhängig vom Netzwerk-Routing darunter. Ein kompromittierter MikroTik kann die BGP-Routen nicht einfach umschreiben und damit Zugriff auf andere Standorte erzwingen, weil der Datenverkehr trotzdem durch den authentifizierten Overlay-Node laufen muss.
Wo die Zero-Trust-Eigenschaften wirklich greifen
Verschlüsselung und Authentifizierung auf dem Transport: Jede Verbindung zwischen zwei Nodes ist WireGuard — Ende-zu-Ende verschlüsselt, mit Mutual Authentication. Es gibt keine unverschlüsselte “interne” Kommunikation im Overlay. Wer keinen gültigen Schlüssel hat, sieht nichts.
ACL-Durchsetzung unabhängig vom physischen Netz: Die Headscale-Policy gilt auf dem Overlay, nicht am Perimeter. Wenn die Policy besagt, dass tag:backup nur 192.168.10.50:8007 erreichen darf, dann wird diese Verbindung auf dem Subnet-Router-Node selbst durchgesetzt — nicht an einer Firewall, an der man vorbeirouten könnte.
Key Expiry: Nodes verlieren nach konfigurierter Zeit ihre Berechtigung und müssen sich re-authentifizieren. Vertrauen wird aktiv erneuert, nicht dauerhaft gewährt.
Minimale Exposition: Headscale und DERP-Relay sind die einzigen öffentlich erreichbaren Endpunkte. Kein Standort-Gateway hat eine öffentliche IP oder eingehende Verbindungen — alles initiiert outbound ins Overlay.
Die ehrliche Einschränkung
Headscale sieht den Subnet Router als Node — nicht die einzelnen Hosts dahinter. Die ACL-Policy kann den Backup-Subnet-Router auf einen bestimmten Port einschränken, aber sie kann nicht unterscheiden, ob der Traffic von 192.168.20.5 oder 192.168.20.99 kommt. Feingranulare Per-Host-Policies innerhalb eines Subnetzes erfordern Tailscale-Clients auf jedem einzelnen Gerät.
Für ein Homelab oder ein KMU mit überschaubarer Segmentierung ist das kein Problem. Für Zero Trust im Sinne von “jeder Workload hat seine eigene Identität” braucht man Tailscale auf jedem Host — dann werden Subnet Router überflüssig, aber der Verwaltungsaufwand steigt entsprechend.
Dieses Setup ist also kein vollständiges ZTNA — es ist ein deutlicher Schritt in diese Richtung, mit pragmatischen Kompromissen bei der Granularität.
Wo man Tailscale direkt einsetzt — und warum
Für besonders kritische Nodes lohnt es sich, den Subnet-Router-Umweg zu umgehen und Tailscale direkt auf dem Host zu installieren. Der Node bekommt dann eine eigene Identität im Tailnet — Headscale sieht nicht “das Homelab-Subnetz”, sondern genau diesen einen Host, mit eigener ACL und eigenem Tag.
In diesem Setup gilt das bereits für die MikroTik-Router selbst: über tailscale-mikrotik ist jeder MikroTik ein eigenständiger Node, nicht ein transparenter Routing-Hop. Die ACL kann einzelne MikroTik-Instanzen gezielt einschränken — der Offsite-Backup-Router darf zum Beispiel nur mit dem Homelab kommunizieren, nicht mit dem Remote-Arbeitsplatz.
Darüber hinaus drei weitere Szenarien aus meinem Setup:
Notebook unterwegs. Ein Laptop auf einem fremden Netz — Café, Hotel, Kunde — ist ein höheres Risiko als ein stationärer Server im eigenen Rack. Mit Tailscale direkt auf dem Notebook bekommt es seinen eigenen Node-Eintrag und ein eigenes Tag (tag:notebook). Die ACL kann es auf genau das beschränken, was unterwegs gebraucht wird: Proxmox-Web-UI auf einem bestimmten Host, SSH auf den Homelab-Jumphost — sonst nichts. Der Rest des Netzes, insbesondere der Backup-Standort, ist für tag:notebook gar nicht erreichbar. Wird das Notebook gestohlen oder kompromittiert, zieht man den Node-Key in Headscale zurück — alle Verbindungen sind sofort tot, ohne VPN-Konfiguration zu ändern oder Passwörter zu rotieren.
Proxmox Backup Server. Der PBS ist ein High-Value-Target: er enthält Backups aller Systeme. Über den Subnet Router wäre er für alles im Homelab-Tailnet sichtbar, das die Route kennt. Mit Tailscale direkt auf dem PBS-Host bekommt er tag:backup-server und die ACL lässt ausschließlich tag:proxmox-host auf Port 8007 (PBS-Web-UI) und 8005 (Backup-Protokoll) zu. Kein anderer Node — auch nicht der Admin-Laptop — kann direkt auf den PBS zugreifen. Der Backup-Traffic läuft verschlüsselt über WireGuard, ohne dass das Backup-Netz irgendwo geroutet wird.
Host in der DMZ. Ein Server, der nach außen Dienste anbietet (Reverse Proxy, Mailserver, öffentliche API), sollte vom internen Netz isoliert sein — das ist der Zweck einer DMZ. Mit Tailscale direkt auf dem DMZ-Host bekommt er tag:dmz und die ACL erlaubt ausschließlich Management-Traffic vom Admin-Node (SSH, Monitoring-Port). Kein interner Host darf Verbindungen zur DMZ initiieren — nur umgekehrt, und auch das nur für explizit definierte Ports. Der DMZ-Host hat über das Tailnet keinen Zugriff auf das interne Netz, selbst wenn er kompromittiert wird.
Das Muster ist immer gleich: je sensibler ein Host, desto mehr lohnt sich der Aufwand, ihn aus dem Subnet-Router-Modell herauszulösen und mit eigener Identität ins Tailnet zu bringen.
Was Zero Trust nicht löst: Schwache Passwörter, ungepatchte Systeme, Insider-Threats. Zero Trust ist eine Netzwerkarchitektur, kein Ersatz für grundlegendes Security-Hygiene.
WireGuard, Tailscale und Headscale
WireGuard ist ein modernes VPN-Protokoll — schnell, minimalistisch, sicher. Aber WireGuard selbst ist nur das Transportprotokoll: es kümmert sich nicht darum, wie Schlüssel verteilt werden, wie Nodes einander finden oder wie NAT-Traversal funktioniert.
Tailscale baut darauf auf und löst genau diese Probleme. Ein Control Plane verwaltet Schlüssel, koordiniert NAT-Traversal via DERP-Relays (Designated Encrypted Relay for Packets) und stellt MagicDNS bereit. Ergebnis: Man installiert den Tailscale-Client, loggt sich ein, und ist sofort in einem Mesh-Netzwerk mit allen anderen Nodes — ohne manuelle WireGuard-Config, ohne Portfreigaben.
Headscale ist eine selbst-gehostete, Open-Source-Implementierung der Tailscale-Control-Plane. Tailscale-Clients verbinden sich statt zu Tailscale’s Servern zu einem eigenen Headscale-Server. Die Tailscale-Apps (iOS, Android, Linux, Windows) funktionieren unverändert.
| Feature | Tailscale | Headscale |
|---|---|---|
| Control Plane | Tailscale Inc. (SaaS) | Self-Hosted (Go, Docker) |
| Kosten | Kostenlos bis 3 User, dann $6/User/Monat | Nur Server-Kosten (~€4/Monat) |
| Datenschutz | Metadaten bei Tailscale Inc. | Vollständig selbst kontrolliert |
| DERP-Relay | Tailscale-betrieben, global verteilt | Eigener Server notwendig |
| Tailscale-Apps | ✓ | ✓ (Login-Server auf Headscale zeigen) |
| Exit Nodes | ✓ | ✓ |
| Subnet Router | ✓ | ✓ |
| ACL / Policy (HuJSON) | ✓ | ✓ |
| MagicDNS | ✓ | Eingeschränkt |
| Offizieller Support | ✓ | Community |
| Skalierung | Bis zu 100 Nodes kostenlos | Unbegrenzt |
Wann Tailscale: Schneller Start ohne Infrastruktur-Overhead. Kein eigener Server, keine eigene DERP-Infrastruktur. Richtig für Einzelpersonen, kleine Teams, alles unter 100 Nodes.
Wann Headscale: Datenschutz ist wichtig (kein Metadata-Logging bei Dritten), Kosten skalieren mit vielen Nodes, volle Kontrolle über die Infrastruktur, Compliance-Anforderungen. Und: man mag es, Dinge selbst zu betreiben.
Ich nutze Headscale. Die Entscheidung fiel wegen Datenschutz und weil ich ohnehin mehrere Hetzner Dedicated Server für andere Dienste betreibe — der Aufwand für einen weiteren Docker-Container ist überschaubar.
Die Architektur: Mein Homelab — 4 Standorte im Headscale-Mesh
┌─────────────────────────────────────────────────────────────┐
│ Headscale Control Plane │
│ Hetzner Dedicated Server · headscale.example.com │
│ + DERP-Relay (derper) │
└───────────┬─────────────────┬──────────────┬───────────────┘
│ Tailscale │ Overlay │ (WireGuard)
│ │ │
┌────────▼───────┐ ┌───────▼──────┐ ┌────▼──────────────┐
│ Homelab │ │ Offsite │ │ Remote-Arbeitsplatz│
│ AS 65001 │ │ Backup │ │ AS 65003 │
│ 192.168.10/24 │ │ AS 65002 │ │ 192.168.30/24 │
│ │ │ 192.168.20/24│ │ │
│ MikroTik CCR │ │ MikroTik hEX │ │ MikroTik hAP │
│ (Tailscale SR) │ │ (Tailscale SR│ │ (Tailscale SR) │
└────────────────┘ └──────────────┘ └────────────────────┘Das ist mein Homelab. Die vier Standorte sind real und produktiv betrieben — kein Testaufbau. Ein Kundenprojekt mit drei Unternehmensstandorten würde das Homelab- und Offsite-Backup-Segment durch die jeweiligen Firmenstandorte ersetzen; das Hetzner-Segment und der Remote-Arbeitsplatz bleiben identisch.
SR = Subnet Router — der MikroTik selbst, der über das tailscale-mikrotik-Paket von Fluent Networks einen Tailscale-Client direkt auf RouterOS betreibt. Kein separater Linux-Node notwendig.
Routing-Prinzip:
- Der MikroTik ist selbst ein authentifizierter Tailscale-Node mit eigener Identität im Tailnet
- Er advertised sein lokales /24 direkt als Subnet Router ins Overlay
- BGP läuft ebenfalls auf dem MikroTik — Peers sind die Tailscale-IPs der anderen MikroTik-Router
- Ein eigener Linux-Node als Subnet Router ist damit nicht mehr nötig
Hetzner Dedicated Server (AS 65000):
- Headscale Control Plane (Docker)
- DERP-Relay (derper, Docker)
- Exit Node (Tailscale-Client als Exit Node konfiguriert)
- Öffentliche IP: erreichbar von allen Standorten
Homelab (AS 65001):
- Proxmox-Cluster mit mehreren VMs
- MikroTik CCR als Hauptrouter und Tailscale Subnet Router (tailscale-mikrotik)
Offsite Backup (AS 65002):
- Proxmox Backup Server
- MikroTik hEX als Site-Router und Tailscale Subnet Router
- Besonderheit: nur vom Homelab erreichbar (ACL-Policy)
Remote-Arbeitsplatz (AS 65003):
- MikroTik hAP ac² als WLAN-Router und Tailscale Subnet Router
- Voller Zugriff auf Homelab-Ressourcen, kein Zugriff auf Backup-Standort
Headscale aufsetzen
Headscale läuft auf einem Hetzner Dedicated Server in Docker. Neben Headscale läuft dort auch der DERP-Relay.
Docker Compose
services:
headscale:
image: headscale/headscale:latest
container_name: headscale
restart: unless-stopped
ports:
- "8080:8080"
- "9090:9090"
volumes:
- ./config:/etc/headscale
- ./data:/var/lib/headscale
command: serve
derper:
image: ghcr.io/tailscale/derper:latest
container_name: derper
restart: unless-stopped
ports:
- "3478:3478/udp"
- "443:443"
environment:
- DERP_DOMAIN=derp.example.com
- DERP_CERT_MODE=letsencrypt
- DERP_ADDR=:443
- DERP_STUN_PORT=3478config.yaml (Headscale)
server_url: https://headscale.example.com
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090
private_key_path: /var/lib/headscale/private.key
noise:
private_key_path: /var/lib/headscale/noise_private.key
ip_prefixes:
- 100.64.0.0/10
derp:
server:
enabled: false
urls: []
paths:
- /etc/headscale/derp.yaml
auto_update_enabled: false
dns_config:
nameservers:
- 1.1.1.1
domains: []
magic_dns: true
base_domain: headscale.internal
db_type: sqlite3
db_path: /var/lib/headscale/db.sqlite
log:
level: info
acl_policy_path: /etc/headscale/acl.hujsonderp.yaml (eigener DERP-Server)
regions:
900:
regionid: 900
regioncode: de-nbg
regionname: Nuremberg
nodes:
- name: 900a
regionid: 900
hostname: derp.example.com
stunport: 3478
derpport: 443Erste Nodes registrieren
# User anlegen
headscale users create homelab
# Pre-Auth Key für unbeaufsichtigte Nodes
headscale preauthkeys create --user homelab --reusable --expiration 24h
# Node-Status prüfen
headscale nodes list
# Advertised Routes freischalten
headscale routes list
headscale routes enable -r <ROUTE-ID>Nützliche Headscale-Befehle
headscale nodes list
headscale nodes expire -i <NODE-ID>
headscale routes list
headscale preauthkeys list --user homelab
headscale debug fqdns
headscale policy getMikroTik als Tailscale Subnet Router
Statt eines separaten Linux-Nodes übernimmt der MikroTik selbst die Rolle des Tailscale Subnet Routers — über das Open-Source-Paket tailscale-mikrotik von Fluent Networks. Es betreibt einen Tailscale-Client direkt auf RouterOS, ohne dass ein zusätzlicher Host nötig ist.
Das hat einen wichtigen Zero-Trust-Vorteil: Der MikroTik ist im Tailnet ein eigenständiger, authentifizierter Node mit eigener Identität und eigenem WireGuard-Schlüsselpaar — nicht ein transparenter Routing-Hop hinter einem Linux-Node.
Installation
Das Paket wird als RouterOS-Script oder Extras-Package installiert. Details und aktuelle Installationsanleitung im GitHub-Repository. Nach der Installation läuft ein Tailscale-Prozess im Hintergrund von RouterOS.
Login gegen Headscale
/system/script/run tailscale-up login-server=https://headscale.example.com \
advertise-routes=192.168.10.0/24 accept-routes=yes \
auth-key=<PRE-AUTH-KEY>Routes in Headscale freischalten
headscale routes list
# ID Node Prefix Advertised Enabled
# 1 mikrotik-hl 192.168.10.0/24 true false
headscale routes enable -r 1Nach dem Freischalten ist 192.168.10.0/24 für alle berechtigten Nodes im Tailnet erreichbar — direkt über den MikroTik als Subnet Router, ohne Umweg über einen Linux-Zwischenhost.
MikroTik als Site-Router und BGP Speaker
MikroTik RouterOS 7 übernimmt zwei Aufgaben: Site-Router für das lokale LAN und BGP-Speaker, der die lokalen Routen an alle anderen Standorte propagiert. BGP läuft über die Tailscale-Overlay-IPs — das WireGuard-Mesh ist der Transport.
Voraussetzungen
- RouterOS 7.x (BGP-Konfiguration weicht von v6 deutlich ab)
- tailscale-mikrotik installiert und Node in Headscale registriert
- Tailscale-IP des jeweiligen MikroTik als BGP-Neighbor (nicht mehr ein Linux-Node)
BGP-Konfiguration Homelab (AS 65001)
# BGP-Instanz erstellen
/routing bgp template
add name=headscale-mesh as=65001 router-id=100.64.0.1
# Neighbors: je ein Peer pro Remote-Standort
# Tailscale-IP des jeweiligen MikroTik (nicht Linux-Node)
/routing bgp connection
add name=to-hetzner remote.address=100.64.0.10 remote.as=65000 \
local.role=ebgp templates=headscale-mesh output.filter-chain=bgp-out
add name=to-offsite-backup remote.address=100.64.0.20 remote.as=65002 \
local.role=ebgp templates=headscale-mesh output.filter-chain=bgp-out
add name=to-remote-office remote.address=100.64.0.30 remote.as=65003 \
local.role=ebgp templates=headscale-mesh output.filter-chain=bgp-out
# Route-Filter: eigenes /24 advertisen, alles andere akzeptieren
/routing filter rule
add chain=bgp-out rule="if (dst == 192.168.10.0/24) { accept }"
add chain=bgp-out rule="reject"BGP-Konfiguration Offsite Backup (AS 65002)
/routing bgp template
add name=headscale-mesh as=65002 router-id=100.64.0.20
/routing bgp connection
add name=to-homelab remote.address=100.64.0.1 remote.as=65001 \
local.role=ebgp templates=headscale-mesh output.filter-chain=bgp-out
add name=to-hetzner remote.address=100.64.0.10 remote.as=65000 \
local.role=ebgp templates=headscale-mesh output.filter-chain=bgp-out
/routing filter rule
add chain=bgp-out rule="if (dst == 192.168.20.0/24) { accept }"
add chain=bgp-out rule="reject"BGP-Status prüfen
/routing bgp session print
# Flags: E - established
# NAME REMOTE-ADDRESS REMOTE-AS STATE UPTIME
# to-homelab 100.64.0.1 65001 established 2d3h
# to-offsite-backup 100.64.0.20 65002 established 2d3hBFD — schnelle Ausfallerkennnung für BGP
Standardmäßig erkennt BGP einen Verbindungsausfall erst, wenn der Hold-Timer abläuft — bei RouterOS-Defaults dauert das bis zu 90 Sekunden. In der Zeit läuft Traffic weiter ins Nichts, Pakete gehen verloren, die Session steht still. Bei einem Overlay-Netzwerk wie Tailscale ist das besonders relevant: wenn ein WireGuard-Tunnel abbricht, merkt BGP es nicht sofort — der TCP-Socket zum Neighbor bleibt scheinbar offen, solange kein Keepalive scheitert.
BFD (Bidirectional Forwarding Detection) ist ein leichtgewichtiges Protokoll, das genau dieses Problem löst. Es schickt in kurzen Abständen Hello-Pakete zwischen zwei Peers — fällt die Antwort aus, meldet BFD den Link sofort als down und BGP reißt die Session sofort. Erkennungszeiten von unter zwei Sekunden sind realistisch.
BFD-Konfiguration in RouterOS 7
BFD wird global oder pro Interface konfiguriert. Für das Tailscale-Overlay empfehle ich konservativere Timer als im klassischen LAN — WireGuard-Crypto und ggf. DERP-Relay-Latenz können kurze Jitter erzeugen, die bei zu aggressiven Timern zu Flapping führen.
# BFD global für alle Interfaces aktivieren
/routing bfd configuration
add interfaces=all min-rx=300ms min-tx=300ms multiplier=5multiplier=5 bedeutet: nach 5 ausgebliebenen Paketen gilt der Peer als down. Bei 300ms Intervall ergibt das 1,5 Sekunden Erkennungszeit — deutlich schneller als 90 Sekunden, aber robust genug für ein Overlay-Netz.
BGP-Connections mit BFD verbinden
BFD wird direkt in der BGP-Connection-Konfiguration aktiviert. Die bestehenden Connections aus dem vorherigen Abschnitt werden erweitert:
# Homelab (AS 65001) — BGP-Connections mit BFD
/routing bgp connection
add name=to-hetzner remote.address=100.64.0.10 remote.as=65000 \
local.role=ebgp templates=headscale-mesh \
output.filter-chain=bgp-out \
bfd.mode=yes bfd.min-rx=300ms bfd.min-tx=300ms bfd.multiplier=5
add name=to-offsite-backup remote.address=100.64.0.20 remote.as=65002 \
local.role=ebgp templates=headscale-mesh \
output.filter-chain=bgp-out \
bfd.mode=yes bfd.min-rx=300ms bfd.min-tx=300ms bfd.multiplier=5
add name=to-remote-office remote.address=100.64.0.30 remote.as=65003 \
local.role=ebgp templates=headscale-mesh \
output.filter-chain=bgp-out \
bfd.mode=yes bfd.min-rx=300ms bfd.min-tx=300ms bfd.multiplier=5BFD-Status prüfen
/routing bfd session print
# Flags: U - up
# PEER IF STATE UPTIME RX-INTERVAL TX-INTERVAL
# 100.64.0.1 tailscale1 up 2d3h 300ms 300ms
# 100.64.0.10 tailscale1 up 2d3h 300ms 300ms
# 100.64.0.20 tailscale1 up 2d3h 300ms 300msAlle BFD-Sessions sollten up zeigen. Wenn eine Session im init-State bleibt, ist die BFD-Gegenstelle nicht konfiguriert oder nicht erreichbar — vor BGP-BFD müssen BFD-Pakete durchkommen.
Was passiert beim Ausfall
Wenn ein WireGuard-Tunnel bricht:
- BFD-Pakete kommen nicht mehr an
- Nach
multiplier × interval(hier: 1,5 Sekunden) markiert BFD den Peer als down - BGP reißt die Session sofort — kein Warten auf den Hold-Timer
- Routen des ausgefallenen Standorts werden aus der Routing-Tabelle entfernt
- Traffic wird nicht mehr dorthin geroutet
Beim Wiederaufbau des Tunnels geht BFD in Sekunden wieder hoch, BGP konvergiert neu, Routen kommen zurück. Die Gesamtzeit vom Ausfall bis zur Wiederherstellung liegt typischerweise unter 10 Sekunden — ein deutlicher Unterschied zu den 90+ Sekunden ohne BFD.
Einschränkung: BFD braucht einen Peer
BFD funktioniert nur, wenn beide Seiten es konfiguriert haben. In einem Mesh mit mehreren MikroTik-Geräten muss jeder Router BFD auf seinen Connections aktivieren. Ein Peer ohne BFD ignoriert die Hello-Pakete — BGP fällt dann auf den Hold-Timer zurück, ohne Fehlermeldung.
Exit Node (Hetzner Dedicated Server)
Der Hetzner Dedicated Server fungiert als Exit Node — ausgehender Internet-Traffic von allen Standorten kann optional über Hetzner geroutet werden. Konfiguration auf dem Linux-Node des Hetzner Servers:
tailscale up \
--login-server https://headscale.example.com \
--advertise-exit-node \
--authkey <PRE-AUTH-KEY>In Headscale freischalten:
headscale routes enable -r <EXIT-NODE-ROUTE-ID>Auf einem Client den Exit Node nutzen:
tailscale up --exit-node=100.64.0.10MikroTik als Exit Node (Internet-Traffic über das lokale Gateway):
# Masquerade für ausgehenden Traffic
/ip firewall nat
add chain=srcnat out-interface=ether1-wan action=masqueradeACL Policy — Zero Trust in der Praxis
Die ACL-Policy in Headscale ist das Herzstück des Zero-Trust-Ansatzes. Standardmäßig kann jeder Node jeden anderen Node erreichen — das ist das Gegenteil von Zero Trust.
Meine Policy (/etc/headscale/acl.hujson):
{
"tagOwners": {
"tag:homelab": ["autogroup:admin"],
"tag:backup": ["autogroup:admin"],
"tag:exit-node": ["autogroup:admin"],
"tag:remote": ["autogroup:admin"]
},
"hosts": {
"homelab-net": "192.168.10.0/24",
"backup-net": "192.168.20.0/24",
"remote-net": "192.168.30.0/24",
"hetzner-net": "10.0.0.0/24"
},
"acls": [
// Homelab darf alles erreichen
{
"action": "accept",
"src": ["tag:homelab"],
"dst": ["*:*"]
},
// Backup-Standort darf nur PBS-Port auf Homelab
{
"action": "accept",
"src": ["tag:backup"],
"dst": ["192.168.10.50:8007"]
},
// Remote-Arbeitsplatz darf Homelab, aber nicht Backup-Netz
{
"action": "accept",
"src": ["tag:remote"],
"dst": ["homelab-net:*"]
},
// Exit Node für alle erreichbar
{
"action": "accept",
"src": ["*"],
"dst": ["tag:exit-node:*"]
}
]
}Tags auf Nodes setzen:
headscale nodes tag -i <NODE-ID> --tags tag:homelab
headscale nodes tag -i <NODE-ID> --tags tag:backupPolicy testen:
# Verbindung zwischen zwei Nodes prüfen
tailscale ping 192.168.20.1 # vom Homelab zum Backup-Netz
# Status und erlaubte Routen
tailscale status
tailscale netcheck # DERP-Latenz, NAT-TypWas die Policy verhindert: Ein kompromittierter Node im Remote-Büro kann nicht den Backup-Server direkt angreifen — die Policy verweigert diese Verbindung auf Overlay-Ebene, unabhängig vom Netzwerk-Routing.
Betrieb und Monitoring
Headscale CLI Cheatsheet
# Übersicht
headscale nodes list # Alle Nodes, Last-Seen, IP
headscale routes list # Advertised Subnets + Freischalt-Status
headscale preauthkeys list --user homelab
# Node-Management
headscale nodes expire -i <ID> # Key sofort invalidieren
headscale nodes delete -i <ID> # Node entfernen
headscale nodes rename -i <ID> --name neuer-name
# Debugging
headscale debug fqdns # MagicDNS-Namen
headscale policy get # Aktive ACL-Policy ausgebenKey Expiry
Headscale kann Node-Keys automatisch ablaufen lassen. Nach Ablauf muss sich der Node neu authentifizieren. Das ist eine Zero-Trust-Eigenschaft: Vertrauen wird regelmäßig erneuert, nicht dauerhaft gewährt.
# config.yaml
node_update_check_interval: 10m
ephemeral_node_inactivity_timeout: 30mFür Subnet Router (müssen dauerhaft verbunden sein) empfehle ich Expiry zu deaktivieren:
headscale nodes expire -i <ID> --expiry 0Prometheus-Metriken
Headscale stellt Metriken auf Port 9090 bereit:
# prometheus.yml
- job_name: headscale
static_configs:
- targets: ["hetzner-server:9090"]Relevante Metriken: headscale_nodes_total, headscale_routes_total.
DERP-Latenz prüfen
tailscale netcheck
# Report:
# * UDP: true
# * IPv4: yes
# * DERP latency:
# - de-nbg: 8ms (eigener DERP)
# - fra: 11ms (Tailscale Frankfurt, Fallback)Wenn der eigene DERP erreichbar ist, sollte er immer die kürzeste Latenz haben.
Typische Probleme
BGP-Session kommt nicht auf (MikroTik): Tailscale-IP des Neighbors nicht erreichbar → tailscale ping <neighbor-ip> prüfen. Route zum Neighbor im Tailnet nicht freigeschaltet → headscale routes enable prüfen.
DERP-Relay nicht erreichbar: Port 443 und 3478/UDP müssen offen sein. Zertifikat-Probleme bei Let’s Encrypt → Logs des derper-Containers prüfen.
Subnet-Route kommt nicht an: headscale routes list → Advertised aber nicht Enabled? headscale routes enable -r <ID>. IP Forwarding auf dem Subnet Router aktiv? sysctl net.ipv4.ip_forward.
Node taucht nicht auf: Pre-Auth Key abgelaufen → neuen Key erstellen. Falscher --login-server beim tailscale up → URL prüfen.
Kosten und Business Case
Die Rechnung
MPLS Headscale
Monatliche Kosten €2.400 ~€60 (Dedicated Server)
Einmalige Installation €3.000 €0
Vertragsbindung 24 Monate keine
Neuer Standort 2-4 Monate 1 Stunde
Homeoffice-Integration schlecht nativ
TCO über 3 Jahre:
MPLS 3 × 12 × €2.400 = €86.400
Headscale 3 × 12 × €60 = €2.160
Differenz ≈ €84.240Das ist kein Nischen-Use-Case. Das ist der Standard für jedes KMU, das kein Carrier-SLA mit Haftung braucht.
Was man ehrlich kommunizieren muss
Kein garantiertes SLA. Internet-Ausfälle treffen alle Standorte gleichzeitig. MPLS hat dedizierte Leitungen — Headscale nicht. Für unternehmenskritische Prozesse, die keine Internet-Unterbrechung tolerieren, ist MPLS weiterhin die sichere Wahl.
Mehr Eigenverantwortung. Der Headscale-Server muss betrieben, gemonitort und gepatcht werden. Bei MPLS macht das der Carrier. Das setzt technisches Personal voraus.
Kein kommerzieller Support. Wenn etwas nicht funktioniert, gibt es kein Ticket beim Carrier. Community, Dokumentation, eigenes Know-how.
Latenz ist nicht garantiert. BGP-Konvergenz bei Internet-Rerouting kann kurze Unterbrechungen verursachen. MPLS-Leitungen haben definierte Latenzen.
Für wen lohnt es sich
- KMU mit technischem IT-Personal (mindestens eine Person, die Linux-Server und RouterOS kennt)
- Unternehmen mit vielen Remote-Mitarbeitern — die sind bei MPLS schon nicht eingebunden
- Unternehmen mit wechselnden Standort-Anforderungen (Projektbüros, Pop-up-Locations)
- Alle, die Kosten reduzieren und dafür Komplexität selbst tragen wollen
Vom Homelab zur Kundeninstallation
Das Homelab läuft produktiv — aber “produktiv” im eigenen Lab bedeutet: ich trage den Schaden selbst, wenn etwas ausfällt. Bei einem Kunden gelten andere Maßstäbe. Was vor einem Deployment noch zusätzlich nötig ist:
- Headscale in HA (zwei Instanzen, gemeinsame SQLite oder PostgreSQL) oder regelmäßige Backups der Headscale-Datenbank
- Monitoring mit Alerting (Headscale-Node offline, DERP-Latenz steigt)
- Dokumentiertes Runbook: was tun wenn Headscale-Server nicht erreichbar?
- Change-Management: wer darf neue Nodes hinzufügen, wer darf Policy ändern?
- Regelmäßige Key-Rotation und Node-Expiry-Policy
Der technische Aufwand für diese Punkte ist überschaubar. Das Ergebnis: ein flexibles, günstiges WAN-Netzwerk mit echten Zero-Trust-Eigenschaften — ohne Carrier-Abhängigkeit.
In meinem Homelab betreibe ich das Setup seit gut einem Jahr. Ein einziger Ausfall: der Hetzner Server war 20 Minuten nicht erreichbar, in dieser Zeit keine Verbindung zwischen Standorten. Bei einem Kunden wäre das eine Störung — bei MPLS wäre es das auch, aber dann jemand anderes’ Problem. Das ist der eigentliche Trade-off, und man sollte ihn kennen, bevor man unterschreibt.



