Headscale : héberger son propre serveur de coordination Tailscale

Tailscale simplifie WireGuard en gérant automatiquement les clés, les routes et la découverte des pairs via ses serveurs de coordination. Headscale reimplemente ce serveur de coordination en open source, permettant de l’héberger soi-même. Vous gardez le client Tailscale (qui ne change pas), mais le plan de contrôle tourne sur votre infrastructure.

Architecture : comment ça fonctionne

Dans Tailscale standard :

[Client A] ──→ [Serveurs Tailscale] ←── [Client B]
                    ↓ coordination
               [Client A] ←────────────→ [Client B]
                     (tunnel WireGuard direct)

Avec Headscale :

[Client A] ──→ [Votre serveur Headscale] ←── [Client B]
                    ↓ coordination
               [Client A] ←────────────────→ [Client B]
                     (tunnel WireGuard direct, identique)

Le trafic de données reste pair-à-pair (WireGuard direct). Seule la coordination (échange de clés publiques, gestion des ACLs, authentification) passe par Headscale.

Installation avec Docker

# docker-compose.yml
services:
  headscale:
    image: headscale/headscale:latest
    container_name: headscale
    volumes:
      - ./config:/etc/headscale
      - headscale-data:/var/lib/headscale
    ports:
      - "8080:8080"
      - "9090:9090"   # métriques Prometheus (optionnel)
    command: serve
    restart: unless-stopped

volumes:
  headscale-data:

Configuration

# config/config.yaml
server_url: https://headscale.mon-domaine.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   # plage Tailscale standard

derp:
  server:
    enabled: false   # utiliser les serveurs DERP Tailscale par défaut
  urls:
    - https://controlplane.tailscale.com/derpmap/default

db_type: sqlite
db_path: /var/lib/headscale/db.sqlite

dns_config:
  magic_dns: true
  base_domain: mon-reseau.internal
  nameservers:
    - 1.1.1.1

Exposition avec Caddy (HTTPS requis)

# Caddyfile
headscale.mon-domaine.com {
    reverse_proxy headscale:8080
}

Headscale nécessite HTTPS — les clients Tailscale refusent une connexion en HTTP.

Gestion des utilisateurs et nœuds

Headscale s’administre via la CLI headscale dans le container :

# Alias pratique
alias hs='docker exec headscale headscale'

# Créer un utilisateur (équivalent d'un "tailnet")
hs users create alice

# Lister les utilisateurs
hs users list

# Générer une clé d'enregistrement pour un nœud
hs preauthkeys create --user alice --expiration 24h

# Lister les nœuds enregistrés
hs nodes list

# Supprimer un nœud
hs nodes delete --identifier 3

Connecter un client Tailscale à Headscale

Sur n’importe quel appareil avec le client Tailscale installé :

# Linux
sudo tailscale up --login-server https://headscale.mon-domaine.com

# macOS (depuis le terminal)
sudo tailscale up --login-server https://headscale.mon-domaine.com

# Windows (PowerShell en admin)
tailscale up --login-server https://headscale.mon-domaine.com

La commande affiche une URL de type :

To authenticate, visit: https://headscale.mon-domaine.com/register/nodekey:abc123...

Enregistrez le nœud depuis l’hôte Headscale :

hs nodes register --user alice --key nodekey:abc123...

Ou utilisez une pre-auth key pour l’enregistrement automatique (idéal pour CI/CD ou scripts) :

# Générer la clé
hs preauthkeys create --user alice --expiration 1h --reusable

# Sur le client
sudo tailscale up \
  --login-server https://headscale.mon-domaine.com \
  --authkey tskey-auth-XXXXX

ACLs (contrôle d’accès)

Les ACLs Headscale suivent la même syntaxe que Tailscale. Fichier config/acls.yaml :

acls:
  # Les admins ont accès à tout
  - action: accept
    src: ["tag:admin"]
    dst: ["*:*"]

  # Les développeurs accèdent aux serveurs de dev
  - action: accept
    src: ["tag:dev"]
    dst: ["tag:dev-server:*"]

  # Tout le monde peut pinger
  - action: accept
    src: ["*"]
    dst: ["*:icmp"]

tagOwners:
  tag:admin: ["alice"]
  tag:dev:   ["alice", "bob"]
  tag:dev-server: ["alice"]

Appliquer les ACLs :

hs policy set --policy-file /etc/headscale/acls.yaml

Routes et exit nodes

# Approuver un exit node (pour router tout le trafic via un nœud)
hs routes list
hs routes enable --route 3

# Côté client : utiliser l'exit node
sudo tailscale up --exit-node=100.64.0.3

Headscale UI (interface web)

Headscale est headless par défaut. Des interfaces web communautaires existent :

headscale-ui (goodieshq/headscale-ui) :

# Ajouter au docker-compose.yml
  headscale-ui:
    image: ghcr.io/goodieshq/headscale-ui:latest
    ports:
      - "8081:80"
    restart: unless-stopped
# Caddyfile
headscale.mon-domaine.com {
    handle /web* {
        reverse_proxy headscale-ui:80
    }
    reverse_proxy headscale:8080
}

Métriques Prometheus

Headscale expose des métriques sur le port 9090 :

# prometheus.yml
scrape_configs:
  - job_name: headscale
    static_configs:
      - targets: ["headscale:9090"]

Métriques disponibles : nombre de nœuds, connexions actives, latence des requêtes.

+ Les points forts

  • Contrôle total — aucune dépendance aux serveurs Tailscale pour la coordination. Vos données ne transitent pas par des serveurs tiers
  • Gratuit sans limite — Tailscale gratuit est limité à 3 utilisateurs et 100 appareils. Headscale n’a aucune limite
  • Clients Tailscale inchangés — iOS, Android, Windows, macOS, Linux utilisent le même client officiel
  • Compatible avec l’écosystème Tailscale — Magic DNS, DERP servers, subnet routing, exit nodes
  • Open source — code auditable, pas de black box

- Les points faibles

  • Pas de client mobile officiel — les apps iOS et Android de Tailscale ne permettent pas de changer le serveur de coordination facilement (nécessite une version custom ou un profil MDM)
  • Maintenance à votre charge — mises à jour, sauvegardes, disponibilité du serveur Headscale sont votre responsabilité. Si Headscale tombe, les nœuds existants continuent de communiquer, mais les nouveaux nœuds ne peuvent pas s’enregistrer
  • Pas de support Tailscale — Headscale n’est pas un produit officiel Tailscale. Certaines fonctionnalités récentes (Tailscale SSH, Taildrive) ne sont pas encore implémentées
  • Configuration plus complexe — par rapport à Tailscale “clé en main”, Headscale demande un serveur exposé sur internet, HTTPS configuré, et une gestion manuelle des nœuds

Tailscale vs Headscale

TailscaleHeadscale
HébergementCloud TailscaleVotre serveur
Limite appareils (gratuit)100Illimité
Limite utilisateurs (gratuit)3Illimité
Applications mobiles✅ Officielles⚠️ Workarounds
Tailscale SSH❌ (partiel)
MaintenanceZéroÀ votre charge
PrixGratuit / $6/moisGratuit

En résumé

Headscale est le choix logique dès que vous avez plus de 3 utilisateurs ou que la souveraineté des données est une contrainte. Le réseau mesh WireGuard reste identique — seul le plan de contrôle bascule chez vous. Pour un usage personnel simple avec moins de 100 appareils, Tailscale en mode cloud reste plus pratique. Pour une équipe ou une infrastructure d’entreprise, Headscale supprime à la fois les limites et la dépendance au cloud.


Voir aussi :

  • Tailscale — la version cloud dont Headscale est l’alternative auto-hébergée
  • Coolify — déployer Headscale facilement sur un VPS
  • Portmaster — contrôler les connexions réseau de vos clients Headscale