Mise en place d'un nœud HeadScale

Installation et configuration de HeadScale, une alternative self-hosted à Tailscale, pour créer un réseau mesh WireGuard sécurisé et géré centralement.
Publié le
Statut
Terminé

Présentation du projet

Ce projet consiste à déployer HeadScale, une implémentation open-source du serveur de coordination Tailscale, permettant de créer un réseau mesh WireGuard auto-hébergé avec gestion centralisée des nœuds.

Objectifs

  • Installer HeadScale sur un serveur Linux
  • Comprendre le concept de réseau mesh vs VPN classique
  • Configurer des clients Tailscale avec HeadScale
  • Créer un réseau mesh privé entre plusieurs machines
  • Gérer les ACL (Access Control Lists) pour sécurité
  • Offrir une alternative self-hosted à Tailscale (SaaS)

Contexte technique

Problématique

Les VPN traditionnels (hub-and-spoke) ont des limites :

  • Point central de défaillance (serveur VPN)
  • Latence accrue (tout passe par le hub)
  • Bandwidth limité par le serveur central
  • Configuration complexe pour site-to-site
  • Pas de P2P direct entre clients

Solution mise en œuvre

HeadScale + Tailscale client offre :

  • Réseau mesh : connexions P2P directes entre nœuds
  • Gestion centralisée : coordination via HeadScale
  • NAT traversal : connexions même derrière NAT/firewall
  • Chiffrement de bout en bout (WireGuard)
  • ACL granulaires : contrôle d’accès fin
  • Self-hosted : données sous contrôle

Différence VPN classique vs Mesh

VPN classique (hub-and-spoke)

PLAINTEXT
Client A ──────┐
               │
Client B ──────┼──► Serveur VPN ◄──── Serveur distant
               │    (hub central)
Client C ──────┘

Problème: Tout le trafic passe par le hub
Cliquez pour développer et voir plus

Réseau mesh (Tailscale/HeadScale)

PLAINTEXT
Client A ◄──────────────► Client B
   │  ╲                      ╱  │
   │    ╲   HeadScale      ╱    │
   │      ╲ (coordination)╱      │
   │        ╲            ╱        │
   │          ╲        ╱          │
   ▼            ╲    ╱            ▼
Client C ◄────────╳───────────► Serveur

Avantage: Connexions P2P directes
Cliquez pour développer et voir plus

Réalisation technique

Installation de HeadScale

Environnement serveur :

PLAINTEXT
OS: Debian 12 / Ubuntu 22.04
RAM: 512 MB minimum
CPU: 1 cœur
Disque: 10 GB
Domaine: headscale.entreprise.local
Port: 8080 (HTTP/HTTPS)
Cliquez pour développer et voir plus

Méthode 1 : Binaire natif :

BASH
# Télécharger HeadScale
HEADSCALE_VERSION="0.22.3"
wget https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_amd64

# Installer
sudo mv headscale_${HEADSCALE_VERSION}_linux_amd64 /usr/local/bin/headscale
sudo chmod +x /usr/local/bin/headscale

# Créer les répertoires
sudo mkdir -p /etc/headscale
sudo mkdir -p /var/lib/headscale

# Télécharger la configuration par défaut
wget https://github.com/juanfont/headscale/raw/main/config-example.yaml -O /etc/headscale/config.yaml
Cliquez pour développer et voir plus

Configuration de HeadScale :

YAML
# /etc/headscale/config.yaml
server_url: https://headscale.entreprise.local

listen_addr: 0.0.0.0:8080

# Path pour base de données
db_type: sqlite3
db_path: /var/lib/headscale/db.sqlite

# Namespace par défaut (équivalent à "organisation")
private_key_path: /var/lib/headscale/private.key

# Plage IP du réseau mesh
ip_prefixes:
  - 100.64.0.0/10  # Range Tailscale standard

# DERP servers (relais pour NAT traversal)
derp:
  server:
    enabled: false  # Désactiver si pas besoin de DERP custom
  
  urls:
    - https://controlplane.tailscale.com/derpmap/default

# DNS configuré pour le réseau mesh
dns_config:
  nameservers:
    - 1.1.1.1
    - 8.8.8.8
  domains: []
  magic_dns: true
  base_domain: entreprise.mesh

# Désactiver OIDC si pas utilisé
oidc:
  issuer: ""
  client_id: ""

# Log level
log_level: info

# ACL policy file
acl_policy_path: /etc/headscale/acl.yaml
Cliquez pour développer et voir plus

Fichier ACL :

YAML
# /etc/headscale/acl.yaml
acls:
  # Groupe des administrateurs
  - action: accept
    src:
      - "group:admins"
    dst:
      - "*:*"
  
  # Serveurs accessibles à tous
  - action: accept
    src:
      - "*"
    dst:
      - "tag:servers:*"
  
  # Bloquerssh depuis internet vers prod
  - action: accept
    src:
      - "group:devs"
    dst:
      - "tag:dev-servers:22,80,443"

groups:
  group:admins:
    - user1@entreprise.mesh
    - user2@entreprise.mesh
  
  group:devs:
    - dev1@entreprise.mesh
    - dev2@entreprise.mesh

tagOwners:
  tag:servers:
    - group:admins
  tag:dev-servers:
    - group:admins
    - group:devs
Cliquez pour développer et voir plus

Service systemd :

INI
# /etc/systemd/system/headscale.service
[Unit]
Description=headscale controller
After=syslog.target
After=network.target

[Service]
Type=simple
User=headscale
Group=headscale
ExecStart=/usr/local/bin/headscale serve
Restart=always
RestartSec=5

# Sécurité
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/headscale /var/run/headscale

[Install]
WantedBy=multi-user.target
Cliquez pour développer et voir plus

Démarrage :

BASH
# Créer utilisateur headscale
sudo useradd -r -s /bin/false -d /var/lib/headscale headscale

# Permissions
sudo chown -R headscale:headscale /etc/headscale /var/lib/headscale

# Activer et démarrer
sudo systemctl enable headscale
sudo systemctl start headscale
sudo systemctl status headscale
Cliquez pour développer et voir plus

Configuration Nginx (reverse proxy)

NGINX
# /etc/nginx/sites-available/headscale
server {
    listen 80;
    listen [::]:80;
    server_name headscale.entreprise.local;
    
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name headscale.entreprise.local;

    ssl_certificate /etc/ssl/certs/headscale.crt;
    ssl_certificate_key /etc/ssl/private/headscale.key;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        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;
        
        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
Cliquez pour développer et voir plus

Gestion des utilisateurs et nœuds

Créer un namespace (utilisateur) :

BASH
# Créer un namespace "admin"
headscale users create admin

# Lister les namespaces
headscale users list
Cliquez pour développer et voir plus

Générer une clé d’enregistrement :

BASH
# Générer une clé préauthentifiée (pour enregistrer un nœud)
headscale preauthkeys create --user admin --reusable --expiration 24h

# La clé générée sera utilisée par le client Tailscale
Cliquez pour développer et voir plus

Configuration des clients Tailscale

Sur un client Linux :

BASH
# Installer Tailscale
curl -fsSL https://tailscale.com/install.sh | sh

# Se connecter au serveur HeadScale
sudo tailscale up --login-server=https://headscale.entreprise.local --authkey=[PREAUTH_KEY]

# Vérifier
sudo tailscale status
sudo tailscale ip -4
Cliquez pour développer et voir plus

Sur Windows :

  1. Installer Tailscale depuis tailscale.com
  2. Modifier le registry pour pointer vers HeadScale :
PLAINTEXT
HKEY_LOCAL_MACHINE\SOFTWARE\Tailscale IPN\
└─ LoginURL = https://headscale.entreprise.local
Cliquez pour développer et voir plus
  1. Lancer Tailscale et utiliser la clé préauth

Sur mobile (Android/iOS) :

  1. Installer Tailscale depuis le store
  2. Paramètres > Use custom control server
  3. Entrer : https://headscale.entreprise.local
  4. Utiliser la clé préauth pour s’authentifier

Gestion des nœuds (CLI)

BASH
# Lister tous les nœuds enregistrés
headscale nodes list

# Voir les détails d'un nœud
headscale nodes show [NODE_ID]

# Supprimer un nœud
headscale nodes delete [NODE_ID]

# Voir les routes annoncées
headscale routes list

# Approuver une route (subnet routing)
headscale routes enable -r [ROUTE_ID]

# Renommer un nœud
headscale nodes rename [NODE_ID] nouveau-nom

# Expirer un nœud (le forcer à se reconnecter)
headscale nodes expire [NODE_ID]
Cliquez pour développer et voir plus

Résultats obtenus

✅ HeadScale déployé et opérationnel
✅ Réseau mesh créé avec 8 nœuds
✅ Connexions P2P établies automatiquement
✅ ACL configurées pour sécurité granulaire
✅ Latence minimale (P2P direct)
✅ NAT traversal fonctionnel
✅ Alternative self-hosted à Tailscale (SaaS)

Compétences développées

  • Déploiement de solutions mesh networking
  • Configuration de HeadScale avancée
  • Gestion d’ACL pour sécurité réseau
  • Compréhension du NAT traversal
  • Administration de réseaux overlay
  • Configuration multi-plateforme (Linux, Windows, mobile)

Architecture du réseau mesh

PLAINTEXT
                HeadScale Server
            (Coordination + ACL)
          headscale.entreprise.local
                     │
         ┌───────────┼───────────┐
         │           │           │
    ┌────▼───┐  ┌───▼────┐  ┌───▼────┐
    │ Laptop │  │Serveur │  │ Mobile │
    │  Win   │  │ Linux  │  │Android │
    │100.64. │  │100.64. │  │100.64. │
    │  0.1   │  │  0.2   │  │  0.3   │
    └────┬───┘  └───┬────┘  └───┬────┘
         │          │           │
         └──────────┼───────────┘
              Connexions P2P
           (WireGuard mesh)
Cliquez pour développer et voir plus

Avantages de HeadScale

vs Tailscale (SaaS)

AspectHeadScaleTailscale
Coût⚡ Gratuit (self-hosted)💰 Payant (> 3 users)
Données⚡ Chez vous⚠️ Cloud Tailscale
Personnalisation⚡ Complète⚠️ Limitée
Support⚠️ Communauté⚡ Support officiel
Fonctionnalités✓ Core features⚡ Toutes features

vs VPN traditionnel

AspectMesh (HeadScale)VPN hub-and-spoke
Performance⚡ P2P direct⚠️ Via hub
Latence⚡ Minimale⚠️ Doublée
Résilience⚡ Pas de SPOF❌ Hub = SPOF
Configuration⚡ Auto mesh⚠️ Manuelle
Scalabilité⚡ Excellente⚠️ Limitée

Fonctionnalités avancées

Subnet routing

Permettre à un nœud de router un sous-réseau entier :

BASH
# Sur le nœud Linux qui route le subnet
sudo tailscale up --advertise-routes=192.168.1.0/24

# Sur HeadScale, approuver la route
headscale routes list
headscale routes enable -r [ROUTE_ID]

# Les autres nœuds peuvent maintenant accéder au subnet
ping 192.168.1.50  # Serveur dans le subnet
Cliquez pour développer et voir plus

Exit node

Utiliser un nœud comme sortie Internet :

BASH
# Sur le nœud exit node
sudo tailscale up --advertise-exit-node

# Sur HeadScale
headscale routes list
headscale routes enable -r [EXIT_NODE_ROUTE]

# Sur un autre nœud, utiliser l'exit node
sudo tailscale up --exit-node=[EXIT_NODE_IP]
Cliquez pour développer et voir plus

MagicDNS

Résolution de noms automatique :

BASH
# Avec MagicDNS activé dans config.yaml
ping laptop.entreprise.mesh  # Résout vers 100.64.0.1
ssh serveur.entreprise.mesh  # SSH direct par nom
Cliquez pour développer et voir plus

Points clés d’apprentissage

  • HeadScale coordonne mais ne transite pas le trafic utilisateur
  • Les connexions sont P2P quand possible (même derrière NAT)
  • STUN/DERP permettent le NAT traversal (comme WebRTC)
  • Les ACL sont évaluées côté serveur mais appliquées côté client
  • Chaque nœud a une IP unique dans la plage 100.64.0.0/10
  • Le protocole sous-jacent est WireGuard (même sécurité)

Sécurité

Bonnes pratiques :

ACL strictes par défaut (deny all)
HTTPS obligatoire pour HeadScale
Clés préauth avec expiration courte
Rotation régulière des clés
Logs d’audit activés
Segments réseau (groupes d’accès)
MFA si intégration OIDC

Monitoring

BASH
# Santé du service
systemctl status headscale

# Logs en temps réel
journalctl -u headscale -f

# Statistiques nœuds
headscale nodes list

# Voir les connexions actives
headscale debugdump
Cliquez pour développer et voir plus

Dépannage

Nœud ne se connecte pas :

BASH
# Vérifier les logs du nœud
sudo tailscale status
sudo tailscale netcheck

# Vérifier sur HeadScale
headscale nodes list
headscale debugdump
Cliquez pour développer et voir plus

Pas de connexion P2P (relais DERP) :

BASH
# Vérifier le NAT traversal
sudo tailscale netcheck

# Forcer punch holes
sudo tailscale ping [NODE_IP]
Cliquez pour développer et voir plus

Perspectives d’amélioration

  • Intégration avec OIDC (Keycloak, Authentik) pour SSO
  • Configuration de DERP servers personnalisés pour performances
  • Mise en place de monitoring (Prometheusexporter)
  • Automatisation de déploiement (Ansible/Terraform)
  • Haute disponibilité avec HeadScale en cluster
  • Intégration avec CMDB pour inventaire automatique
  • ACL dynamiques basées sur attributs OIDC
  • Audit et compliance avec logs centralisés

Commencer la recherche

Saisissez des mots-clés pour rechercher des articles

↑↓
ESC
⌘K Raccourci