- Published on
Headscale – Installation mit Docker und Caddy
- Authors
- Name
- Tobias Steltner
Intro
In dieser Anleitung zeige ich, wie man Headscale mit Docker und Caddy installiert. Headscale ist eine selbstgehostete Open-Source-Implementierung des Tailscale-Kontrollservers. Tailscale ist ein benutzerfreundliches VPN, das auf WireGuard basiert und eine einfache und sichere Netzwerkverbindung zwischen Geräten ermöglicht, ohne komplexe Konfigurationen. Es nutzt eine Zero-Trust-Architektur, um den Netzwerkverkehr zu sichern und erleichtert den Zugriff auf Ressourcen, unabhängig vom Standort der Benutzer.
- 1. Grundvoraussetzung
- 2. Vorwort
- 3. Docker Setup
- 4. Einrichtung von Headscale
- 5. DynDNS Setup (optional)
- 6. Quellen:
1. Grundvoraussetzung
- Docker & Docker Compose v2 (Debian / Ubuntu)
- Ein VPS mit fester IP und diese sollte per A-Record auf eine Domain zeigen (FQDN)
- Port 80, 443, 443udp offen + SSH
2. Vorwort
Bevor wir loslegen, möchte ich kurz mein Setup erklären. Ich nutze es seit 4 Wochen in meinem Homelab und bin damit sehr zufrieden. Es ist wichtig zu wissen, dass Headscale sich noch in der Entwicklung befindet, aber es läuft bei mir sehr stabil.
Mein Ziel war es, bestimmte Dienste öffentlich zugänglich zu machen und gleichzeitig bestmöglich abzusichern. Dafür verwende ich ein Setup mit Traefik und CrowdSec. Für besonders sensible Anwendungen wie Vaultwarden suchte ich jedoch eine zusätzliche Sicherheitsmaßnahme. Ich wollte für diese Anwendungen SSL-Zertifikate haben, die nur für mich oder ausgewählte Personen zugänglich sind. Um das zu realisieren, habe ich Headscale eingerichtet.
Das heißt im Klartext: Mein Vaultwarden läuft komplett lokal bei mir zu Hause, hier ist kein Port geöffnet. Verbunden mit Headscale kann ich mir dann allerdings SSL-Zertifikate besorgen und mein Vaultwarden nur von einer bestimmten IP zugänglich machen.
Der Headscale-Server verbindet alle benötigten Server einfach und schnell per VPN. Über einen integrierten Caddy-Container kann ich ausgewählten Diensten SSL-Zertifikate zuweisen und den Zugriff über IP-Blockregeln steuern.
Um es noch komfortabler zu gestalten, habe ich einen sehr günstigen VPS (1 € pro Monat) mit 1 CPU und 1 GB RAM gemietet, was völlig ausreicht. Ich verwende eine Domain für öffentliche Dienste, die über Traefik läuft, und eine zweite Domain für meine internen Dienste. Diese nenne ich hier public.com und private.com.
Auf diese Weise könnte man generell Dienste nach außen freigeben, ohne Ports am Heimrouter öffnen zu müssen, aber das war nicht mein Hauptziel. Ich hoffe, meine Grundidee ist klar, und nun zur Installation.
3. Docker Setup
Hier kümmern wir uns erstmal darum das die Container sauber laufen.
3.1 Ordner anlegen
Ordner Struktur anlegen.
mkdir -p /opt/containers/ && cd /opt/containers
Git Repro clonen.
git clone https://github.com/2TAP2B/headscale.git
Weitere Ordner erstellen
cd headscale
mkdir -p caddy/config caddy/data
3.2 Caddyfile anpassen
nano /opt/containers/headscale/caddy/Caddyfile
Hier bitte in der zweiten Zeile headscale.private.com entsprechend anpassen.
3.3 Headscale config anpassen
nano /opt/containers/headscale/headscale/config/config.yml
Die Server Url:
server_url: https://headscale.private.com
bitte anpassen.
Die Base Doamin:
base_domain: headscale.private.com
bitte anpassen.
3.4 Container starten
docker compose -f /opt/containers/headscale/docker-compose.yml up -d
4. Einrichtung von Headscale
Öffnet nun:
https://headscale.private.com/web
Natürlich anpassen die Domain
Hier solltest du nun im WebUI von Headscale ankommen und ein API Fehler taucht auf.
Wir gehen nochmal ins hauptverzeichnis rein.
cd /opt/containers/headscale/
Jetzt erstellen wir uns unseren API-Token.
docker compose exec headscale headscale apikeys create
Kopiere den API Token unter Settings in das Feld Headscale API Key und klicke einmal Test Server.
Jetzt erstellen wir erstmal einen User. Unter dem Punkt User, Add User.
Jetzt kann man sich den Tailscale Client von der offiziell Tailscale Seite downloaden.
Tailscale Download
Für Linux zB.
curl -fsSL https://tailscale.com/install.sh | sh
Die Client Software ist Open Source. Die Verbindung via Windows oder Linux ist sehr einfach und mit einem Befehl zu realiseren.
Öffnet diesen Link (entsprechend angepasst auf deine Domain)
https://headscale.private.com/windows
Dort steht nun:
tailscale login –login-server https://headscale.private.com
Haut den Befehl in die Konsole bzw. Windows-Powershell und folgt den Anweisungen im Fenster.
Dann müsstet ihr den neuen Client per SSH auf dem Headscale-Server hinzufügen, oder ihr kopiert den “mkey:bblabla” und fügt diesen im Web-UI unter “Device View”, “New Device” ein, wählt einen Benutzer und schon seid ihr mit Headscale verbunden.
Auch der Server auf dem Headscale läuft muss manuell als Client registriert werden, wenn er Teil des Netzwerkes sein soll!
4.1 Der klassische VPN: IP verschleiern
Um jetzt nicht nur einen VPN zu haben, sondern auch ein Proxy der unseren Traffic durch die entsprechende IP Routet zu erstellen, müssen wir einen der Clients zur “Exit Node” machen. Das machen wir ganz einfach über die CLI beim gewünschten Client per
tailscale set --advertise-exit-node
Jetzt sagen wir dem Betriebssystem noch das wir wirklich den Traffic weiterleiten wollen.
echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/99-vpn.conf
echo 'net.ipv6.conf.all.forwarding = 1' >> /etc/sysctl.d/99-vpn.conf
sysctl -p /etc/sysctl.d/99-vpn.conf
Zu guter letzt müssen wir im WebUI noch die angegebene Route freigeben. Wählt dafür das entsprechende Device aus und drückt auf “Pending.”
5. DynDNS Setup (optional)
Wenn ihr wie ich einen ganz normalen Internetanschluss mit einer dynamischen IP habt und den Datenverkehr eures VPN über diese wechselnde IP leiten möchtet, habe ich eine einfache Lösung. Ich habe ein kleines Skript erstellt, das das Problem der wechselnden IP-Adressen behebt.
Das Bashscript sollte auch per git clone schon vorhanden sein.
#!/bin/bash
DDNS_DOMAIN="public.com"
CADDYFILE="/opt/containers/headscale/caddy/Caddyfile"
# Erhalte die aktuelle IP-Adresse von der DDNS-Domain
CURRENT_IP=$(dig +short $DDNS_DOMAIN)
# Prüfe, ob die aktuelle IP-Adresse gültig ist
if [[ -z "$CURRENT_IP" ]]; then
echo "Fehler: Konnte die IP-Adresse von $DDNS_DOMAIN nicht ermitteln."
exit 1
fi
# Ersetze den Platzhalter im Caddyfile durch die aktuelle IP-Adresse
sed -i "s/CURRENT_IP_PLACEHOLDER/$CURRENT_IP/" $CADDYFILE
# Starte Caddy neu, um die Änderungen zu übernehmen
docker compose -f /opt/containers/headscale/docker-compose.yml restart caddy
# Füge den Platzhalter zurück, um zukünftige Ersetzungen zu ermöglichen
sed -i "s/$CURRENT_IP/CURRENT_IP_PLACEHOLDER/" $CADDYFILE
Ihr müsst nur bei DDNS_DOMAIN=”euredyndnsdomain.de”
eintragen.
Dann machen wir es noch ausführbar.
chmod +x /opt/containers/headscale/ip.sh
Und erstellen einen Cronjob, damit es automatisch die IP aktualisiert.
crontab -e
Am Ende der Datei fügst du folgende Zeile ein:
0 4 * * * /opt/containers/headscale/ip.sh
5.1 Troubleshooting
Wenn ihr das Setup mit DynDNS und diesem Skript verwendet, müsst ihr Folgendes beachten: Nach einem Neustart eures Stacks solltet ihr das ip.sh-Skript erneut ausführen. Andernfalls wird der Reverse Proxy nicht richtig funktionieren.
6. Quellen:
https://github.com/juanfont/headscale
https://blog.gurucomputing.com.au/Smart%20VPNS%20with%20Headscale/Setting%20up%20Headscale