Tailscale a popularisé l'idée d'un VPN mesh basé sur WireGuard, avec un control plane SaaS qui gère l'authentification, la distribution des clés et les ACL. Le client est open source ; le serveur de coordination, lui, ne l'est pas. Pour les organisations qui veulent garder la maîtrise de leurs métadonnées d'authentification ou éviter une dépendance à un service tiers, ce point pose question.
Headscale comble ce vide : c'est une réimplémentation open source du control plane Tailscale, compatible avec tous les clients officiels. Cet article détaille l'architecture, le déploiement, les fonctionnalités supportées, et les limites par rapport à la version SaaS.
Plan de l'article
- Qu'est-ce que Headscale
- Architecture : ce que fait un control plane
- Fonctionnalités supportées
- Limites par rapport à Tailscale SaaS
- Déploiement avec Docker
- Configuration des ACL
- Authentification OIDC
- Cas d'usage pertinents
Qu'est-ce que Headscale
Headscale est un projet open source démarré en 2020 par Juan Font Alonso (juanfont sur GitHub), distribué sous licence BSD-3-Clause. Il implémente le protocole de coordination Tailscale du côté serveur, en restant strictement compatible avec les clients officiels (Linux, macOS, Windows, iOS, Android, FreeBSD, OpenBSD, tvOS).
La dernière version stable au moment de la rédaction est la v0.28.0, publiée le 4 février 2026. Le dépôt cumule plus de 38 000 étoiles GitHub, et le projet a été adopté par Canonical (paquet snap officiel), TrueNAS (catalogue d'apps), NixOS (module natif).
Le positionnement est clair : Headscale fournit un control plane self-hosted qui remplace login.tailscale.com. Les clients officiels Tailscale s'enregistrent contre votre serveur Headscale plutôt que contre l'infrastructure SaaS. Les communications entre nœuds restent strictement chiffrées de bout en bout via WireGuard, comme avec Tailscale standard.
Trois éléments distinguent Headscale d'un VPN classique :
- Une compatibilité native avec les clients Tailscale, sans fork ni patch. La même app
tailscale upqui pointe vers le SaaS pointe vers votre Headscale via--login-server. - Une architecture single-binary Go, sans dépendance externe. SQLite par défaut pour le stockage.
- Un modèle simple : un seul tailnet par instance Headscale. Pour mutualiser plusieurs organisations, on déploie plusieurs instances ou on utilise les utilisateurs/tags pour cloisonner.
Architecture : ce que fait un control plane
Pour comprendre Headscale, il faut savoir ce qu'un control plane Tailscale gère et ce qu'il ne gère pas. Le control plane est responsable de :
- L'authentification initiale des nœuds (clé pré-partagée, OIDC, web auth).
- La gestion des identités (utilisateurs, tags, groupes).
- La distribution des clés publiques WireGuard entre nœuds autorisés à communiquer.
- L'application des ACL (qui peut parler à qui).
- Le serveur DERP (relais TCP) pour les nœuds qui ne peuvent pas établir de tunnel direct.
- MagicDNS et split DNS.
Ce qu'il ne fait pas : transporter le trafic. Une fois l'enregistrement effectué et les clés échangées, le trafic est strictement pair-à-pair via WireGuard. Le control plane peut tomber, les nœuds continuent de communiquer entre eux tant qu'ils ont déjà négocié leurs clés et que NAT traversal tient.
┌─────────────────────┐
│ Headscale server │
│ - SQLite │
│ - DERP embarqué │
│ - OIDC (optionnel) │
└──────────┬──────────┘
│ HTTPS (auth, keys)
┌──────────────┼──────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ Client A │◄─┤ Client B │◄─┤ Client C │
└───────────┘ └───────────┘ └───────────┘
WireGuard pair-à-pair (UDP)
Fonctionnalités supportées
La page Features de la documentation officielle liste précisément ce que Headscale couvre. Voici les fonctionnalités majeures.
| Fonctionnalité | Statut |
| Dual stack IPv4/IPv6 | Supporté |
| Subnet routers | Supporté |
| Exit nodes | Supporté |
| DERP server embarqué | Supporté |
| Access Control Lists (ACL) avec autogroups et auto-approvers | Supporté |
| MagicDNS, split DNS, search domains | Supporté |
| OpenID Connect (OIDC) pour l'enregistrement | Supporté |
| Pre-auth keys et enregistrement web | Supporté |
| Tags et nœuds éphémères | Supporté |
| Tailscale SSH | Supporté |
| Taildrop (partage de fichiers) | Supporté |
Côté clients, Headscale s'engage à supporter les 10 dernières releases du client Tailscale officiel sur toutes les plateformes listées.
Limites par rapport à Tailscale SaaS
Headscale n'est pas un clone exhaustif de Tailscale. Plusieurs fonctionnalités du SaaS ne sont pas implémentées ou le sont partiellement, et il faut les connaître avant d'engager une migration.
OIDC groups absents des ACL. La doc le dit explicitement : on peut authentifier un utilisateur via Keycloak ou Authentik, mais on ne peut pas écrire une règle ACL qui s'appuie sur l'appartenance à un groupe OIDC. Le contournement consiste à passer par les tags Headscale ou à mapper manuellement les utilisateurs.
Funnel et Serve incomplets. Les fonctionnalités Tailscale qui exposent un service interne sur Internet (Funnel) ou en HTTPS local (Serve) ne sont pas implémentées de manière complète. Pour un usage qui les requiert, le SaaS reste nécessaire.
Network flow logs non supportés. L'observabilité avancée du trafic n'est pas exposée. Pour de l'audit fin, on s'appuie sur les logs des clients eux-mêmes ou sur une instrumentation externe.
Un seul tailnet par instance. Là où Tailscale SaaS gère nativement le multi-organisation, Headscale fonctionne sur un modèle single-tenant. Pour héberger plusieurs entités, on déploie plusieurs instances ou on cloisonne via les utilisateurs et tags.
PostgreSQL déprécié. Depuis la version 0.23, l'équipe encourage SQLite. PostgreSQL reste supporté en legacy mais n'est plus la voie recommandée. Pour la haute disponibilité, on s'oriente vers une réplication SQLite type LiteFS plutôt qu'un cluster PostgreSQL.
Déploiement avec Docker
Le projet privilégie en réalité les binaires officiels (paquets DEB, RPM, snap) pour des raisons de support, mais le déploiement par container reste officiellement documenté et largement utilisé en production. Les images sont publiées sur GitHub Container Registry. Voici un docker-compose minimal :
services:
headscale:
image: ghcr.io/juanfont/headscale:0.28.0
container_name: headscale
restart: unless-stopped
read_only: true
ports:
- '8080:8080'
- '9090:9090'
volumes:
- ./config:/etc/headscale:ro
- ./lib:/var/lib/headscale
command: serve
Le port 8080 expose l'API et l'enregistrement des nœuds, 9090 les métriques Prometheus. Le répertoire config/ contient config.yaml (configuration principale), lib/ accueille la base SQLite et l'état persistant.
Configuration minimale dans config/config.yaml :
server_url: https://headscale.example.com
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
noise:
private_key_path: /var/lib/headscale/noise_private.key
prefixes:
v4: 100.64.0.0/10
v6: fd7a:115c:a1e0::/48
derp:
server:
enabled: true
region_id: 999
region_code: 'headscale'
region_name: 'Headscale Embedded DERP'
stun_listen_addr: '0.0.0.0:3478'
Côté reverse proxy, Headscale se place derrière un Nginx ou Traefik qui termine TLS. Le projet documente précisément la configuration TLS attendue : pas de buffering, support du streaming HTTP/2, et chemins préservés.
Configuration des ACL
Les ACL Headscale reprennent la syntaxe Tailscale (HuJSON), avec quelques ajustements. Exemple type :
{
"groups": {
"group:admin": ["alice@example.com", "bob@example.com"],
"group:dev": ["carol@example.com"]
},
"tagOwners": {
"tag:prod": ["group:admin"],
"tag:ci": ["group:admin"]
},
"acls": [
{
"action": "accept",
"src": ["group:admin"],
"dst": ["*:*"]
},
{
"action": "accept",
"src": ["group:dev"],
"dst": ["tag:ci:*"]
},
{
"action": "accept",
"src": ["tag:ci"],
"dst": ["tag:prod:22,80,443"]
}
],
"ssh": [
{
"action": "accept",
"src": ["group:admin"],
"dst": ["tag:prod"],
"users": ["root", "ubuntu"]
}
]
}
Les groups regroupent des utilisateurs, les tagOwners définissent qui peut taguer un nœud, les acls listent les règles de filtrage source/destination, et la section ssh active Tailscale SSH avec la liste des utilisateurs Unix autorisés. La règle est appliquée immédiatement à tous les nœuds connectés via une mise à jour incrémentale.
Authentification OIDC
Headscale supporte l'enregistrement des nœuds via un fournisseur OIDC : Keycloak, Authentik, Okta, Azure AD ou Google Workspace. Configuration type dans config.yaml :
oidc:
only_start_if_oidc_is_available: true
issuer: https://auth.example.com/realms/headscale
client_id: headscale
client_secret_path: /var/lib/headscale/oidc_secret
scope: ['openid', 'profile', 'email']
pkce:
enabled: true
method: S256
expiry: 180d
Au moment de l'enregistrement (tailscale up --login-server=https://headscale.example.com), le client ouvre le navigateur, s'authentifie sur le fournisseur OIDC, et Headscale crée l'utilisateur correspondant. C'est la bascule recommandée pour toute organisation qui dispose déjà d'un IdP.
Limite à connaître : les groupes retournés par le provider ne sont pas utilisables dans les ACL (cf. section précédente). La pratique consiste à mapper les utilisateurs vers des tags Headscale via des règles tagOwners.
Cas d'usage pertinents
Headscale apporte une vraie valeur dans quatre contextes.
Souveraineté des métadonnées
Pour une organisation soumise à des contraintes de localisation des données ou qui ne souhaite pas confier ses métadonnées d'authentification (qui se connecte, depuis où, vers quoi) à un tiers, le control plane self-hosted répond directement à l'exigence. Toutes les données restent sur l'infrastructure que vous contrôlez.
Environnements air-gapped
Les infrastructures déconnectées d'Internet ne peuvent pas s'appuyer sur le SaaS Tailscale. Un Headscale local dans un réseau isolé permet de bénéficier du modèle mesh sans sortir du périmètre. Le DERP embarqué fournit le relais TCP sans dépendance externe.
Plateformes mutualisées
Pour un hébergeur ou un MSP qui veut proposer un VPN mesh à ses clients, déployer un Headscale par client donne un cloisonnement strict (un tailnet par instance) sans dépendre d'un compte SaaS par client. Le coût marginal d'une instance Headscale supplémentaire est faible.
Infrastructures zero trust hybrides
Pour relier des datacenters, des bureaux, des nœuds edge et des postes nomades sans exposer de bastion ou de VPN concentrateur, le mesh Headscale + clients Tailscale est rapide à déployer. Les exit nodes permettent de router le trafic Internet à travers un point précis si nécessaire, les subnet routers exposent un sous-réseau LAN au reste du tailnet.
Perspectives complémentaires
- Sécuriser SSH avec Tailscale
- WireGuard : le VPN moderne par défaut
- Keycloak SSO et OAuth2
- Architecture zero trust
- Bastion SSH avec MFA
Sources
- Headscale (dépôt GitHub officiel) code, releases, version v0.28.0
- Documentation Headscale, installation, configuration, ACL
- Features supportées, liste officielle
- Client and OS support, plateformes et politique de support
- Container deployment, Docker et docker-compose
Conclusion
Headscale n'est pas une copie complète de Tailscale, mais c'est la voie la plus crédible pour bénéficier du modèle mesh WireGuard sans dépendre d'un control plane SaaS. La compatibilité avec les clients officiels et le support des fonctionnalités les plus demandées (ACL, MagicDNS, OIDC, exit nodes, subnet routers) en font une option viable pour la majorité des déploiements internes. Les limites concernent surtout les fonctionnalités d'exposition publique (Funnel, Serve) et l'observabilité avancée, sujets qui sont rarement bloquants pour un usage interne.


