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)
Client A ──────┐
│
Client B ──────┼──► Serveur VPN ◄──── Serveur distant
│ (hub central)
Client C ──────┘
Problème: Tout le trafic passe par le hubRéseau mesh (Tailscale/HeadScale)
Client A ◄──────────────► Client B
│ ╲ ╱ │
│ ╲ HeadScale ╱ │
│ ╲ (coordination)╱ │
│ ╲ ╱ │
│ ╲ ╱ │
▼ ╲ ╱ ▼
Client C ◄────────╳───────────► Serveur
Avantage: Connexions P2P directesRéalisation technique
Installation de HeadScale
Environnement serveur :
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)Méthode 1 : Binaire natif :
# 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.yamlConfiguration de HeadScale :
# /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.yamlFichier ACL :
# /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:devsService systemd :
# /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.targetDémarrage :
# 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 headscaleConfiguration Nginx (reverse proxy)
# /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";
}
}Gestion des utilisateurs et nœuds
Créer un namespace (utilisateur) :
# Créer un namespace "admin"
headscale users create admin
# Lister les namespaces
headscale users listGénérer une clé d’enregistrement :
# 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 TailscaleConfiguration des clients Tailscale
Sur un client Linux :
# 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 -4Sur Windows :
- Installer Tailscale depuis tailscale.com
- Modifier le registry pour pointer vers HeadScale :
HKEY_LOCAL_MACHINE\SOFTWARE\Tailscale IPN\
└─ LoginURL = https://headscale.entreprise.local- Lancer Tailscale et utiliser la clé préauth
Sur mobile (Android/iOS) :
- Installer Tailscale depuis le store
- Paramètres > Use custom control server
- Entrer : https://headscale.entreprise.local
- Utiliser la clé préauth pour s’authentifier
Gestion des nœuds (CLI)
# 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]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
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)Avantages de HeadScale
vs Tailscale (SaaS)
| Aspect | HeadScale | Tailscale |
|---|---|---|
| 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
| Aspect | Mesh (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 :
# 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 subnetExit node
Utiliser un nœud comme sortie Internet :
# 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]MagicDNS
Résolution de noms automatique :
# Avec MagicDNS activé dans config.yaml
ping laptop.entreprise.mesh # Résout vers 100.64.0.1
ssh serveur.entreprise.mesh # SSH direct par nomPoints 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
# 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 debugdumpDépannage
Nœud ne se connecte pas :
# Vérifier les logs du nœud
sudo tailscale status
sudo tailscale netcheck
# Vérifier sur HeadScale
headscale nodes list
headscale debugdumpPas de connexion P2P (relais DERP) :
# Vérifier le NAT traversal
sudo tailscale netcheck
# Forcer punch holes
sudo tailscale ping [NODE_IP]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