Files
Tailscale2Headscale/README.md
2025-12-14 22:38:07 +01:00

11 KiB
Raw Permalink Blame History

Tailscale2Headscale

Headscale + Tailscale Homelab Migration

⚠️ Version publique / anonymisée Tous les noms de domaine, IP et clés ont été remplacés par des placeholders. Remplace toutes les valeurs <...> par les tiennes avant dutiliser ce document.


1. Objectif

Mettre en place un contrôle Tailscale autohébergé avec Headscale pour remplacer le control plane Tailscale SaaS, tout en :

  • gardant les clients Tailscale classiques (Linux, macOS, Android, Home Assistant, etc.) ;
  • centralisant la gestion sur un serveur Headscale accessible en HTTPS ;
  • évitant les bugs classiques (mauvais port, mauvais --login-server, clés expirées, etc.).

Ce README récapitule :

  • larchitecture retenue ;
  • la configuration Headscale (service + Web admin + reverse proxy) ;
  • la configuration des clients Tailscale ;
  • les problèmes rencontrés et les solutions pour ne plus tomber dedans.

2. Architecture globale

2.1. Composants

  • Serveur Headscale

    • Type : LXC / VM Linux (Debianlike)
    • Rôle : serveur headscale + Web UI (headscaleadmin)
    • IP locale : <HEADSCALE_LAN_IP> (ex : 192.168.1.xxx)
    • Nom interne : <HEADSCALE_HOSTNAME> (ex : headscale)
  • Reverse proxy (facultatif mais recommandé)

    • Logiciel : caddy (ou nginx/traefik)
    • Port HTTP interne Headscale : 8080
    • Port HTTPS public : 443
    • Nom de domaine : <HEADSCALE_PUBLIC_FQDN> (ex : headscale.example.com)
    • Certificats : Lets Encrypt ou équivalent
  • Clients Tailscale

    • Serveur Proxmox VE : <PVE_HOST>
    • Proxmox Backup Server : <PBS_HOST>
    • NAS (OMV ou autre) : <NAS_HOST>
    • Containers / VM : <CT_DOCKER_PTR>, <CT_JENKINS>, etc.
    • Home Assistant : Add-on Tailscale
    • macOS : client Tailscale officiel
    • Android : app Tailscale officielle

Tout ce petit monde parle au contrôle plane : https://<HEADSCALE_PUBLIC_FQDN>.


3. Installation de Headscale (serveur)

3.1. Prérequis

Sur la machine Headscale (LXC/VM) :

apt update
apt install -y headscale sqlite3 ca-certificates curl

Créer le répertoire de configuration :

mkdir -p /etc/headscale

3.2. Fichier de configuration config.yaml (exemple)

⚠️ Important : Adapter les valeurs server_url, listen_addr, grpc_listen_addr, db_path, etc.

# /etc/headscale/config.yaml
server_url: "https://<HEADSCALE_PUBLIC_FQDN>"
listen_addr: "0.0.0.0:8080"
grpc_listen_addr: "0.0.0.0:50443"

ip_prefixes:
  - "100.64.0.0/10"

derp:
  server:
    enabled: true
    region_id: 999
    region_code: "homelab"
    region_name: "Homelab DERP"
  paths: []

# Base SQLite (simple à gérer pour un homelab)
db_type: "sqlite"
db_path: "/var/lib/headscale/db.sqlite"

tls_cert_path: ""
tls_key_path: ""

log:
  level: "info"

dns_config:
  override_local_dns: false
  magic_dns: false

3.3. Service systemd

Le paquet Debian fournit généralement un service headscale.service. Vérifier :

systemctl enable --now headscale
systemctl status headscale --no-pager

4. Web admin : headscaleadmin

4.1. Dossier et configuration

Headscaleadmin est en général servi par un serveur web (caddy/nginx), souvent depuis :

/var/www/headscale-admin

ou :

/opt/headscale-admin

Cette UI se connecte à lAPI Headscale (port 8080 dans notre cas).


5. Reverse proxy (Caddy)

Cest ici quon a eu une galère : mélange de ports 80 et 8080. Résultat : clients Tailscale qui pointaient sur :8080 alors que le proxy écoutait en :80 → 404 ou connexion impossible.

5.1. Exemple de config Caddy

# /etc/caddy/Caddyfile

<HEADSCALE_PUBLIC_FQDN> {
    encode gzip

    # Proxy API Headscale (port interne 8080)
    reverse_proxy /api/* 127.0.0.1:8080

    # UI headscale-admin statique
    root * /var/www/headscale-admin
    file_server
}

5.2. Points critiques

  • Le serveur Headscale écoute sur :8080.
  • Le reverse proxy écoute en :443 (et :80 pour HTTP → redirect vers 443).
  • Les clients Tailscale nont pas besoin du port dans --login-server sils passent par HTTPS standard :--login-server=https://<HEADSCALE_PUBLIC_FQDN>
  • Si tu décides de garder un port non standard (:8443 par ex.), il faut le mettre partout :
    • dans server_url de Headscale ;
    • dans --login-server= côté clients ;
    • dans la config du reverse proxy.

6. Gestion des utilisateurs et clés dans Headscale

6.1. Créer un user

headscale users create <USERNAME>
headscale users list

Exemple :

headscale users create syleric

6.2. Créer une preauth key

headscale preauthkeys create --user <USER_ID> --reusable --ephemeral=false

Exemple :

headscale users list
# ID | Name | Username | Email | Created
# 1  |      | $user  |       | ...

headscale preauthkeys create --user 1 --reusable --ephemeral=false
# -> renvoie une clé du type : 548fd8... (ne pas mettre ici en clair)

🔁 Si tu doutes dune clé, tu peux la regénérer et supprimer lancienne.


7. Enregistrement des clients Tailscale

7.1. Schéma global

Pour chaque machine, on fait :

tailscale logout || true
tailscale down || true

tailscale up \
  --login-server=https://<HEADSCALE_PUBLIC_FQDN> \
  --auth-key=<PREAUTH_KEY> \
  --accept-dns=false \
  --accept-routes=false \
  --reset

On utilise --accept-dns=false pour éviter que Headscale override le DNS local du homelab, et --accept-routes=false tant quon ne met pas en place de routes subnets poussées via Headscale.


8. Cas particulier : macOS

8.1. Utiliser le binaire Tailscale macOS

Depuis le Mac :

/Applications/Tailscale.app/Contents/MacOS/Tailscale status
/Applications/Tailscale.app/Contents/MacOS/Tailscale logout || true
/Applications/Tailscale.app/Contents/MacOS/Tailscale down || true

Puis :

sudo /Applications/Tailscale.app/Contents/MacOS/Tailscale up \
  --login-server=https://<HEADSCALE_PUBLIC_FQDN> \
  --auth-key=<PREAUTH_KEY> \
  --accept-dns=false \
  --accept-routes=false \
  --reset

Si la clé est valide et le --login-server accessible, tu dois voir :

/Applications/Tailscale.app/Contents/MacOS/Tailscale status
# 100.64.0.X  <MAC_HOSTNAME>  <USER>  macOS  -

9. Cas particulier : Home Assistant (add-on Tailscale)

9.1. Configurer ladd-on

Dans la configuration de ladd-on Tailscale (interface Home Assistant) :

authkey: "<PREAUTH_KEY>"
hostname: "homeassistant"
login_server: "https://<HEADSCALE_PUBLIC_FQDN>"
userspace_networking: true  # ou false selon ton besoin
accept_dns: false
accept_routes: false

Ensuite, côté Headscale, tu verras un node :

headscale nodes list
# ...
# homeassistant | homeassistant | ... | 100.64.0.9, ...

Si lexpiration a été mise par erreur, tu peux la corriger :

headscale nodes expire --identifier <NODE_ID> --expiry 0001-01-01T00:00:00Z

⚠️ Attention : commande expire sert à fixer une date dexpiration. Pour ne pas expirer, il faut utiliser la valeur spéciale 0001-01-01T00:00:00Z.


10. Android (smartphone & tablette)

10.1. Changer de serveur de login

Sur Android, il ny a pas (encore) de bouton clair dans lUI pour changer de login-server vers un Headscale custom.

La méthode fiable :

  1. Se déconnecter de Tailscale sur lapp (logout).

  2. Effacer les données de lappli (ou désinstaller/réinstaller) pour repartir de zéro.

  3. Lors du premier tailscale up par CLI dans Termux (si tu utilises Termux + binaire Linux), lancer :

    tailscale up \
      --login-server=https://<HEADSCALE_PUBLIC_FQDN> \
      --auth-key=<PREAUTH_KEY> \
      --accept-dns=false \
      --accept-routes=false \
      --reset
    
  4. Côté Headscale, tu verras apparaître le nouveau node avec hostname (souvent localhost si tu utilises Termux) ; tu peux ensuite le renommer côté Headscale :

    headscale nodes rename --identifier <NODE_ID> <NOM_SOUHAITÉ>
    

💡 Attention : renommer dans Headscale ne change pas le hostname système Android/Termux, mais ça rend la liste Headscale plus lisible.


11. Vérifications globales

11.1. Depuis Headscale

headscale nodes list

Tu dois voir quelque chose du genre :

ID | Hostname       | Name          | IP addresses                  | Connected | Expired
1  | jenkins        | jenkins       | 100.64.0.1, fd7a:115c:a1e0::1 | online    | no
2  | docker-ptr     | docker-ptr    | 100.64.0.2, fd7a:115c:a1e0::2 | online    | no
3  | nas            | nas           | 100.64.0.5, fd7a:115c:a1e0::5 | online    | no
...

11.2. Depuis un client (ex : PBS ou PVE)

tailscale status

Tu dois voir tous les peers (Mac, Android, HA, etc.) avec leurs IPs 100.64.0.X.


12. Pièges rencontrés & leçons apprises

12.1. Mauvais port dans le reverse proxy

  • Symptôme :
    • curl http://127.0.0.1:8080 → 404 ou rien
    • Tailscale up semble bloquer ou ne jamais arriver à joindre le serveur
  • Cause :
    • Caddy/nginx servait sur le port 80, mais on essayait dappeler :8080 depuis lextérieur.
  • Solution :
    • Standardiser :
      • Headscale API : :8080 (interne)
      • Reverse proxy : :443 (public)
      • --login-server=https://<HEADSCALE_PUBLIC_FQDN> (pas de port explicite si 443)

12.2. Mélange Tailscale SaaS / Headscale

  • Symptôme :
    • Le client Tailscale ouvre une URL https://login.tailscale.com/...
  • Cause :
    • Pas de --login-server ou valeur incorrecte → le client repart sur le SaaS officiel.
  • Solution :
    • Toujours vérifier la commande tailscale up :
      tailscale up --login-server=https://<HEADSCALE_PUBLIC_FQDN> ...
      

12.3. Expiration des nodes

  • Symptôme :
    • Dans headscale nodes list, la colonne Expired passe à yes.
  • Cause :
    • Mauvaise manipulation de la commande expire avec une date proche du présent.
  • Solution :
    • Pour un node qui ne doit pas expirer :
      headscale nodes expire --identifier <ID> --expiry 0001-01-01T00:00:00Z
      

13. Résumé rapide (mode pensebête)

  1. Headscale

    • Config dans /etc/headscale/config.yaml
    • listen_addr: 0.0.0.0:8080
    • server_url: "https://<HEADSCALE_PUBLIC_FQDN>"
  2. Reverse proxy

    • Terminate TLS (Lets Encrypt)
    • Proxy /api127.0.0.1:8080
    • Servir la Web UI statique (/var/www/headscale-admin)
  3. Utilisateur & clés

    • headscale users create <USERNAME>
    • headscale preauthkeys create --user <ID> --reusable --ephemeral=false
  4. Clients

    • Commande type :
      tailscale logout || true
      tailscale down || true
      tailscale up \
        --login-server=https://<HEADSCALE_PUBLIC_FQDN> \
        --auth-key=<PREAUTH_KEY> \
        --accept-dns=false \
        --accept-routes=false \
        --reset
      
  5. Validation

    • headscale nodes list
    • tailscale status depuis plusieurs machines

Avec cette checklist, tu peux reconstruire tout ton tailnet Headscale sans rete prendre 2 jours de galère, et tu peux publier ce README (après remplacement des placeholders) sur un dépôt public sans exposer ta vraie infra.