Headscale selbst hosten: Tailscale-Mesh-VPN ohne Cloud-Abhängigkeit für KMU
Headscale ersetzt den Tailscale Control Server auf eigener Infrastruktur: Installation auf Ubuntu, Reverse Proxy mit TLS, Nutzer und Pre-Auth-Keys, ACL-Policy, Subnet-Router und Exit-Node mit Headscale 0.29.
Geprüft am 29.09.2026 · für headscale 0.29.4
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Mit WireGuard braucht jedes neue Gerät ein Schlüsselpaar, Einträge auf jedem Peer und Firewall-Anpassungen. Tailscale nimmt das ab, betreibt den Koordinationsserver aber in der eigenen Cloud und rechnet pro Nutzer ab. Headscale ist eine Open-Source-Reimplementierung dieses Control Servers für Ihren eigenen Server, ohne Geräte-Limits.
Voraussetzungen
- Ubuntu-Server 22.04 LTS oder 24.04 LTS (VPS oder dediziert, öffentlich erreichbar), x86_64 oder ARM64
- Öffentliche IPv4-Adresse und ein FQDN (z. B.
hs.example.com) mit DNS-A-Eintrag - Gültiges TLS-Zertifikat – Let's Encrypt via Certbot (Nginx) oder automatisch via Caddy
- Offene Ports: TCP/443 (HTTPS), TCP/80 (Let's Encrypt, Weiterleitung), UDP/3478 (STUN, nur mit eingebettetem DERP-Server)
- Mindestens 1 vCPU, 1 GB RAM, 10 GB SSD (für einige Dutzend Geräte)
- Tailscale-Client auf jedem Endgerät (Windows, macOS, Linux, iOS, Android)
- Grundkenntnisse Linux-Serverbetrieb und Nginx/Caddy-Konfiguration
Schritt 1: Headscale vs. Tailscale-Cloud vs. WireGuard – die richtige Wahl treffen
Alle drei Optionen basieren auf WireGuard, unterscheiden sich aber in Verwaltungsaufwand, Datensouveränität und Kosten:
| Kriterium | WireGuard (rein) | Tailscale Cloud | Headscale (self-hosted) |
|---|---|---|---|
| Peer-Verwaltung | Manuell je Gerät | Automatisch | Automatisch |
| NAT-Traversal | Manuell/kein | Automatisch (DERP) | Automatisch (DERP) |
| Datensouveränität | Vollständig | US-Server | Vollständig |
| DSGVO-Risiko | Gering | Metadaten auf US-Servern | Gering (eigene Infra) |
| Geräte-Limits | Keine | Begrenzt im kostenlosen Tarif | Keine |
| Abrechnung | Nur eigener Server | Je Nutzer und Monat | Nur eigener Server |
| Einrichtungsaufwand | Hoch | Minimal | Mittel (~90 Min.) |
Empfehlung: Headscale eignet sich für KMU, die mehr als 3 Nutzer haben, Wert auf Datensouveränität legen und bereit sind, einen einfachen Linux-Server zu betreiben. Tailscale-Cloud bleibt die bessere Wahl, wenn das IT-Team sehr klein ist und SSO-Integration (Azure AD, Google) ohne eigene OIDC-Infrastruktur benötigt wird. Reines WireGuard ist dann sinnvoll, wenn ausschließlich Server-zu-Server-Verbindungen mit statischen IPs nötig sind. Aktuelle Tarife nennt die Preisseite von Tailscale.
Verifizieren: Sie haben einen Server mit öffentlicher IP, einen DNS-A-Eintrag für den Headscale-FQDN und die Freigabe, die Ports 80 und 443 dafür zu nutzen.
Schritt 2: Headscale installieren
Headscale wird als Debian-Paket ausgeliefert; die SQLite-Datenbank legt es selbst an.
# Headscale 0.29.4 herunterladen und installieren (Ubuntu 22.04/24.04)
HEADSCALE_VERSION="0.29.4"
HEADSCALE_ARCH="amd64" # arm64 für ARM-Server
wget -O headscale.deb "https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_${HEADSCALE_ARCH}.deb"
sudo apt install ./headscale.deb
sudo systemctl enable --now headscale
Headscale lauscht per Default nur auf 127.0.0.1:8080 (HTTP), 127.0.0.1:9090 (Metriken) und 127.0.0.1:50443 (gRPC). TLS terminiert hier der Reverse Proxy; alternativ holt Headscale selbst Let's-Encrypt-Zertifikate.
Verifizieren: headscale version zeigt 0.29.4, systemctl status headscale meldet active (running).
Schritt 3: Headscale konfigurieren
Passen Sie in /etc/headscale/config.yaml mindestens folgende Werte an (Schlüssel wie in der Beispielkonfiguration von Version 0.29):
# /etc/headscale/config.yaml (Auszug, übrige Werte wie ausgeliefert)
server_url: https://hs.example.com
listen_addr: 127.0.0.1:8080
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
trusted_proxies:
- 127.0.0.1/32
- ::1/128
tls_cert_path: ""
tls_key_path: ""
noise:
private_key_path: /var/lib/headscale/noise_private.key
prefixes:
v4: 100.64.0.0/10
v6: fd7a:115c:a1e0::/48
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
log:
level: info
policy:
mode: file
path: /etc/headscale/acl.json
dns:
magic_dns: true
base_domain: vpn.example.com
nameservers:
global:
- 1.1.1.1
derp:
server:
enabled: false
urls:
- https://controlplane.tailscale.com/derpmap/default
auto_update_enabled: true
update_frequency: 3h
Wichtig: base_domain für MagicDNS (hier vpn.example.com) muss sich von der Server-URL-Domain (hs.example.com) unterscheiden, sonst entstehen DNS-Loops; kein abschließender Punkt. Bis zur Policy-Datei (Schritt 7) bleibt path: "", sonst startet Headscale nicht. Nach Änderungen: sudo systemctl restart headscale.
Verifizieren: sudo headscale configtest endet ohne Fehler, journalctl -u headscale -n 20 zeigt keine Meldungen zu unbekannten oder veralteten Schlüsseln.
Schritt 4: Reverse Proxy mit TLS einrichten
Tailscale-Clients erwarten HTTPS auf Port 443 mit einem gültigen Zertifikat. Zwei Optionen:
Option A: Nginx mit Certbot
# /etc/nginx/sites-available/headscale
server {
listen 443 ssl;
server_name hs.example.com;
ssl_certificate /etc/letsencrypt/live/hs.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hs.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_buffering off;
}
}
Zwingend: proxy_http_version 1.1, die Upgrade/Connection-Header und proxy_buffering off, sonst brechen langlebige WebSocket-Verbindungen ab. Ausführlich: Nginx als Reverse Proxy mit TLS einrichten.
Option B: Caddy (empfohlen – automatisches TLS)
# /etc/caddy/Caddyfile
hs.example.com {
reverse_proxy 127.0.0.1:8080
}
Caddy holt und erneuert das Zertifikat automatisch und leitet WebSockets ohne Zusatzkonfiguration weiter. Cloudflare-Proxy (oranges Wolkensymbol) und Cloudflare Tunnel werden nicht unterstützt, da Cloudflare das Tailscale-Protokoll nicht korrekt weiterleitet; nur DNS-only (graues Symbol).
Verifizieren: curl -sI https://hs.example.com/health liefert HTTP/2 200 mit gültigem Zertifikat.
Schritt 5: Nutzer, Gruppen und Pre-Auth-Keys anlegen
„Users“ entsprechen den Tailscale-Namespaces; jedes Gerät gehört einem User, hier einer je Abteilung. Pre-Auth-Keys erwarten in 0.29 die numerische User-ID aus headscale users list:
# Nutzer (Abteilungen) anlegen
sudo headscale users create marketing
sudo headscale users create buchhaltung
sudo headscale users create it-admin
# IDs der User anzeigen
sudo headscale users list
# Einmaliger Pre-Auth-Key (24 Stunden gültig), USER_ID aus der Liste
sudo headscale preauthkeys create --user <USER_ID> --expiration 24h
# Wiederverwendbarer Key (z. B. für automatisiertes Onboarding, 30 Tage)
sudo headscale preauthkeys create --user <USER_ID> --reusable --expiration 720h
# Alle Keys auflisten
sudo headscale preauthkeys list
Sicherheitshinweis: Im Produktionsbetrieb kurzlebige Einmal-Keys statt wiederverwendbarer Keys mit langer Laufzeit nutzen. Der Key wird nur beim Anlegen vollständig angezeigt.
Verifizieren: sudo headscale users list zeigt die drei User, sudo headscale preauthkeys list die angelegten Keys mit Ablaufdatum.
Schritt 6: Geräte verbinden
Auf dem Client läuft der offizielle Tailscale-Client, der Login-Server wird als Parameter übergeben.
# Linux / macOS: Interaktiver Login (öffnet Browser-Authentifizierung)
tailscale up --login-server https://hs.example.com
# Mit Pre-Auth-Key (kein Browser-Login, ideal für Server-Onboarding)
tailscale up --login-server https://hs.example.com --authkey <PREAUTHKEY>
# Ohne Pre-Auth-Key: Node serverseitig registrieren
# (die Auth-ID aus der Ausgabe bzw. Webseite des Clients übernehmen)
sudo headscale auth register --user marketing --auth-id <AUTH_ID>
# Alle verbundenen Nodes anzeigen
sudo headscale nodes list
Windows und macOS haben GUI-Clients; auf iOS/Android tragen Sie den Server in der App unter „Account“ → „Use custom coordination server“ ein.
Verifizieren: sudo headscale nodes list zeigt das Gerät als online, auf dem Client meldet tailscale status eine IP aus 100.64.0.0/10.
Schritt 7: ACL-Policies für Abteilungstrennung
ACL-Policies nutzen das HuJSON-Format von Tailscale. Ohne Policy-Datei ist jeder Verkehr erlaubt, mit acls gilt Default-Deny. User schreiben Sie mit angehängtem @. IT-Admins erhalten Vollzugriff, Marketing und Buchhaltung bleiben intern:
// /etc/headscale/acl.json
{
"groups": {
"group:it-admin": ["it-admin@"],
"group:marketing": ["marketing@"],
"group:buchhaltung": ["buchhaltung@"]
},
"acls": [
// IT-Admin darf alles
{ "action": "accept", "src": ["group:it-admin"], "dst": ["*:*"] },
// Marketing darf nur innerhalb der eigenen Gruppe kommunizieren
{ "action": "accept", "src": ["group:marketing"], "dst": ["group:marketing:*"] },
// Buchhaltung darf nur innerhalb der eigenen Gruppe kommunizieren
{ "action": "accept", "src": ["group:buchhaltung"], "dst": ["group:buchhaltung:*"] }
]
}
# Policy prüfen und neu einlesen (ohne Neustart)
sudo headscale policy check --file /etc/headscale/acl.json
sudo systemctl reload headscale
Beim ersten Mal path: /etc/headscale/acl.json unter policy eintragen und neu starten; spätere Änderungen übernimmt systemctl reload headscale. Tailscale empfiehlt für neue Policies Grants statt ACLs, Headscale unterstützt beide. Server-Absicherung: Linux-Server absichern mit UFW und Fail2ban.
Verifizieren: journalctl -u headscale -n 20 zeigt nach dem Reload keine Policy-Fehler. Ein Marketing-Gerät erreicht per tailscale ping ein anderes Marketing-Gerät, ein Buchhaltungs-Gerät dagegen nicht.
Schritt 8: Subnet-Router – LAN-Subnetz ins Tailnet einbinden
Ein Subnet-Router macht ein lokales Netz (z. B. Büro-LAN 192.168.10.0/24) im Tailnet erreichbar, ohne Tailscale auf jedem LAN-Gerät:
# IP-Forwarding aktivieren (persistent via sysctl)
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.conf
# Subnetz bekanntmachen (auf dem Node, der das LAN sieht)
sudo tailscale up --login-server https://hs.example.com --advertise-routes=192.168.10.0/24
# Serverseitig: Route genehmigen (NODE_ID aus list-routes)
sudo headscale nodes list-routes
sudo headscale nodes approve-routes --identifier <NODE_ID> --routes 192.168.10.0/24
# Linux-Clients nehmen Subnet-Routen erst nach Freigabe an
sudo tailscale set --accept-routes
Fallstrick: Transient aktiviertes IP-Forwarding (echo 1 > /proc/sys/net/ipv4/ip_forward) geht beim Neustart verloren. Nutzen Sie /etc/sysctl.d/.
Verifizieren: sudo headscale nodes list-routes zeigt 192.168.10.0/24 unter „Approved“ und „Serving“, ein Client erreicht per ping eine Adresse im Büro-LAN.
Schritt 9: Exit-Node konfigurieren
Ein Exit-Node leitet den gesamten Internetverkehr eines Clients über einen Knoten, etwa für Homeoffice-Geräte mit Büro-IP:
# Auf dem Node, der als Exit-Node dienen soll:
sudo tailscale up --login-server https://hs.example.com --advertise-exit-node
# Serverseitig freischalten (0.0.0.0/0 genügt, ::/0 wird automatisch mit freigegeben)
sudo headscale nodes list-routes
sudo headscale nodes approve-routes --identifier <NODE_ID> --routes 0.0.0.0/0
# Auf dem Client-Gerät den Exit-Node nutzen:
sudo tailscale set --exit-node=<TAILSCALE-IP-DES-EXIT-NODES>Auch der Exit-Node braucht aktiviertes IP-Forwarding wie in Schritt 8.
Verifizieren: Auf dem Client zeigt curl -s https://ifconfig.me die öffentliche IP des Exit-Nodes.
Schritt 10: DERP-Relay und Node-Verwaltung
DERP-Server leiten Verbindungen weiter, wenn keine direkte Verbindung zustande kommt. Default ist die öffentliche DERP-Map von Tailscale (alle 3 Stunden aktualisiert). Für Relays ohne Tailscale-Server betreiben Sie eigene DERP-Server und setzen urls: [].
# DERP-Status auf einem Client prüfen
tailscale debug derp-map
tailscale debug derp headscale
# Alle Nodes auflisten
sudo headscale nodes list
# Einzelnen Node manuell ablaufen lassen (z. B. bei Gerätetausch)
sudo headscale nodes expire --identifier <NODE_ID>
# Alle Routen prüfen
sudo headscale nodes list-routes
Key-Expiry: Nodes laufen per Default nie ab (Expiry = 0), bei Tailscale-Cloud nach 180 Tagen. Pre-Auth-Keys laufen nach einer Stunde ab. Ein Standard-Ablaufdatum setzen Sie mit node.expiry, einzelne Nodes lassen Sie mit headscale nodes expire ablaufen.
Verifizieren: tailscale debug derp-map listet die erwarteten DERP-Regionen, tailscale netcheck meldet eine erreichbare nächste Region.
Troubleshooting / Typische Fehler
- Client verbindet sich nicht / „Invalid server URL“: Selbstsignierte Zertifikate werden abgelehnt. Zertifikat und Erneuerung prüfen (
sudo certbot renew --dry-run). - WebSocket-Verbindung bricht ab: Nginx-Einstellungen aus Schritt 4 (HTTP/1.1,
Upgrade/Connection,proxy_buffering off) prüfen. - Cloudflare-Proxy (orange) aktiv: Auf „DNS only“ (grau) umschalten.
- MagicDNS löst Hostnamen nicht auf:
base_domainmuss sich von der Domain inserver_urlunterscheiden (Schritt 3). - Subnet-Router funktioniert nach Neustart nicht mehr: IP-Forwarding in
/etc/sysctl.d/99-tailscale.confspeichern (Schritt 8). - Exit-Node wird von macOS/iOS nicht angeboten: In Versionen vor 0.29.4 ein bekannter Fehler; auf die aktuelle Patch-Version aktualisieren.
- Headscale und Tailscale-Client auf demselben Host: Nicht unterstützt (Konflikte bei Subnet-Routing, MagicDNS, Relay); getrennte Hosts verwenden.
- PostgreSQL geplant: Headscale führt PostgreSQL nur noch im „maintenance mode“. Neue Instanzen mit SQLite (Standard) aufsetzen.
- Befehl unbekannt nach Update (
headscale routes,policy apply): Diese Befehle gibt es nicht mehr; Routen verwalten Sie mitheadscale nodes list-routesundapprove-routes. Keine Minor-Version überspringen (z. B. 0.27 → 0.28 → 0.29). - Keine Verbindung hinter doppeltem NAT: Eingebetteten DERP-Server aktivieren (
derp.server.enabled: true) und UDP/3478 freigeben oder eine eigenederper-Instanz betreiben.
Häufige Fragen
Kann ich die offiziellen Tailscale-Apps mit Headscale nutzen?
Ja, auf allen Plattformen, ab Tailscale-Client 1.80 (Login-Server siehe Schritt 6).
Wie groß muss der Server für Headscale sein?
1 vCPU, 1 bis 2 GB RAM und 20 GB SSD; der Control Server liegt nicht im Datenpfad.
Was passiert, wenn mein Headscale-Server ausfällt?
Bestehende Verbindungen bleiben aktiv, solange die WireGuard-Sessions laufen; neue Verbindungen scheitern bis zur Rückkehr des Servers. Ein Backup von /var/lib/headscale/ (SQLite-Datenbank, Private Keys) ist Pflicht, z. B. per Restic-Backup unter Linux und Windows automatisieren.
Brauche ich einen eigenen DERP-Server für vollständige DSGVO-Konformität?
Nicht zwingend. Über die Standard-DERP-Map weitergeleitete Inhalte bleiben Ende-zu-Ende verschlüsselt. Für vollständige Datenlokalisierung siehe Schritt 10.
Wie vergleicht sich die Performance gegenüber reinem WireGuard?
Nein, Headscale liegt nicht im Datenpfad. Die Clients nutzen wireguard-go im Userspace, auf aktuellem Linux dennoch nah an Kernel-WireGuard. Über DERP-Relays begrenzen Relay-Bandbreite und Latenz.
Wann sollte ich lieber bei Tailscale-Cloud bleiben?
Wenn schnelles Onboarding wichtiger ist als Datensouveränität, das IT-Team sehr klein ist oder SSO (Google, Microsoft Entra ID) ohne eigenen OIDC-Dienst nötig ist (siehe Schritt 1).
Was bedeutet „Key-Expiry“ in Headscale konkret?
Node-Keys laufen per Default nie ab, Pre-Auth-Keys nach einer Stunde. Details und die Option node.expiry beschreibt Schritt 10.
Fazit
Headscale liegt zwischen manuell verwaltetem WireGuard und Tailscale-Cloud. Rechnen Sie mit etwa 90 Minuten Einrichtung und planen Sie Updates bewusst, da sich CLI und Konfiguration zwischen Minor-Versionen ändern.
Weiterführende Anleitungen und Quellen
- WireGuard-VPN für Homeoffice und Standortvernetzung einrichten
- Nginx als Reverse Proxy mit TLS einrichten
- Linux-Server absichern mit UFW und Fail2ban
- Restic-Backup unter Linux und Windows automatisieren
Quellen: Headscale auf GitHub (Changelog und Beispielkonfiguration), Headscale-Dokumentation (Installation, Routen, Policy, Reverse Proxy, FAQ).


