📍 Article principal de la série : Headscale 2026 : guide pratique. Lisez le guide général pour la vue d’ensemble.
Trente minutes pour passer d’un VPS vide à un Headscale de production avec HTTPS valide, prêt à accepter vos premiers clients Tailscale. Ce tutoriel détaille la procédure exacte sur Hetzner CX23 (4,51 €/mois) avec Caddy comme reverse proxy. Méthode validée chez plusieurs PME à Dakar, Abidjan, Lomé, et Ouagadougou.
Prérequis
- VPS Hetzner CX23 ou OVH VPS-1 (Debian 12 ou Ubuntu 22.04 LTS).
- Un nom de domaine avec enregistrement DNS A :
headscale.votre-entreprise.com→ IP du VPS. - Accès SSH root.
- Niveau : intermédiaire (Linux, systemd, fichiers YAML).
- Temps estimé : 30 à 45 minutes.
Étape 1 — Préparer le VPS
Mises à jour système et firewall :
apt update && apt upgrade -y
apt install -y ufw fail2ban
ufw allow 22 80 443
ufw allow 41641/udp # DERP / WireGuard
ufw enable
Étape 2 — Installer Headscale via dépôt officiel
curl -fsSL https://github.com/juanfont/headscale/releases/download/v0.23.0/headscale_0.23.0_linux_amd64.deb -o /tmp/headscale.deb
dpkg -i /tmp/headscale.deb
systemctl enable headscale
mkdir -p /etc/headscale /var/lib/headscale
Étape 3 — Configuration de base
Éditer /etc/headscale/config.yaml :
server_url: https://headscale.votre-entreprise.com
listen_addr: 127.0.0.1:8080
metrics_listen_addr: 127.0.0.1:9090
private_key_path: /var/lib/headscale/private.key
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: false
urls:
- https://controlplane.tailscale.com/derpmap/default
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
log:
level: info
dns:
magic_dns: true
base_domain: tailnet.votre-entreprise.com
nameservers:
global:
- 1.1.1.1
- 9.9.9.9
Étape 4 — Configurer Caddy pour HTTPS
apt install -y caddy
Éditer /etc/caddy/Caddyfile :
headscale.votre-entreprise.com {
reverse_proxy 127.0.0.1:8080
encode gzip
log {
output file /var/log/caddy/headscale.log {
roll_size 100MB
roll_keep 7
}
}
}
Recharger Caddy : systemctl reload caddy. Test : curl -I https://headscale.votre-entreprise.com/health. Doit retourner 200 OK.
Étape 5 — Démarrer Headscale
systemctl start headscale
systemctl status headscale
Logs : journalctl -u headscale -f.
Étape 6 — Créer le premier utilisateur et la première preauth key
headscale users create amadou
headscale preauthkeys create --user amadou --expiration 24h --reusable
La sortie contient une clé du type 1234567890abcdef.... Notez-la, elle expire dans 24h.
Étape 7 — Connecter le premier appareil
Sur un poste Linux :
curl -fsSL https://tailscale.com/install.sh | sh
tailscale up --login-server=https://headscale.votre-entreprise.com --auth-key=PREAUTH_KEY
Sur Mac : ouvrir Terminal, brew install --cask tailscale, puis lancer l’app, faire option-clic sur l’icône en haut à droite, choisir « Use Custom Coordination Server », saisir l’URL, puis Login.
Sur iOS / Android : ouvrir Settings dans l’app Tailscale officielle, faire 5 taps sur la version pour activer le mode debug, modifier l’URL du coordination server.
Étape 8 — Vérification
headscale nodes list
Vous voyez votre premier appareil enregistré, avec son IP attribuée (typiquement 100.64.0.1). Test de ping entre deux appareils :
tailscale ping autre-appareil
# Pong from autre-appareil via direct connection
Étape 9 — Configuration OIDC (optionnel mais recommandé)
Pour brancher Authelia ou Authentik comme fournisseur d’identité, ajouter dans config.yaml :
oidc:
issuer: https://auth.votre-entreprise.com
client_id: headscale
client_secret: votre-secret
scope: ["openid", "profile", "email"]
extra_params:
domain_hint: votre-entreprise.com
allowed_users:
- amadou@votre-entreprise.com
Erreurs fréquentes
| Erreur | Cause | Solution |
|---|---|---|
| Client refuse de s’enregistrer | URL serveur incorrecte | Vérifier server_url et listen_addr |
| Pas de connectivité après registration | Port UDP 41641 bloqué | UFW : ufw allow 41641/udp |
| MagicDNS ne résout pas | Base domain non configuré | Définir base_domain dans config + restart |
| Mobile ne trouve pas l’option custom server | Mode dev non activé | 5 taps sur version dans Settings |
| Caddy 502 Bad Gateway | Headscale non démarré | systemctl status headscale |
| Préauth key expirée | Délai 24h dépassé | Régénérer avec --expiration 168h (7j) |
Ce qui dévie dans la pratique locale
Trois ajustements pour une PME africaine. Choix du DERP relay : par défaut Headscale utilise les DERP de Tailscale (US et Europe). Pour optimiser la latence depuis l’Afrique de l’Ouest, vous pouvez auto-héberger un DERP sur un VPS Africa Data Centres (Lagos ou Le Cap) — option avancée. Pour la majorité, les DERP Frankfurt/Paris suffisent. Coût total annuel : 54 €/an de VPS + 12 €/an de domaine = 66 € pour une équipe illimitée. Gestion des employés temporaires : freelances et stagiaires sont fréquents en Afrique de l’Ouest. Headscale + preauth keys à durée limitée (24h, 7j, 30j) gèrent élégamment l’onboarding-offboarding.
Articles connexes
FAQ
Quelle différence entre Tailscale et Headscale au quotidien ? Aucune côté utilisateur. Les clients officiels Tailscale fonctionnent identiquement avec Headscale, l’interface graphique et les commandes CLI sont les mêmes.
Combien de temps prend la migration de Tailscale Cloud ? Pour 30 appareils, comptez une demi-journée pour scripts, une demi-journée pour la bascule. Voir tutoriel dédié.
Headscale supporte-t-il l’IPv6 ? Oui, dual-stack par défaut. Les peers obtiennent une IPv4 dans 100.64.0.0/10 et une IPv6 dans la plage configurée.
Comment monitorer Headscale ? Endpoint /metrics Prometheus, ingestion Grafana. Alertes sur nombre de nodes hors ligne, sur taille SQLite, sur erreurs API.
SQLite suffit pour combien d’appareils ? Jusqu’à 500 appareils confortablement. Au-delà, basculer sur PostgreSQL via database.type: postgres.
Dans la continuité
- 🔝 Retour au guide général : guide pratique Headscale 2026
- Documentation Headscale : headscale.net
- Tutoriel suivant : ACL pour équipe distribuée
Pour appliquer ce tutoriel sur un vrai serveur
Hostinger reste l’option la plus simple pour démarrer. Lien partenaire — votre achat soutient le blog sans surcoût.
Lien d affiliation. Si vous achetez via ce lien, le blog reçoit une petite commission sans surcoût pour vous.
Étape 1 — Pourquoi Headscale plutôt que Tailscale officiel pour une PME africaine
Tailscale est une solution VPN mesh excellente, mais son plan gratuit est limité à 3 utilisateurs et la version Business commence à 6 USD/utilisateur/mois (environ 3 950 FCFA/mois et par utilisateur en janvier 2026). Pour une équipe de 15 personnes à Dakar ou Cotonou, la facture annuelle dépasse 700 000 FCFA. Headscale, le coordinateur libre développé par Juan Font, fait exactement la même chose, gratuitement, sur votre propre VPS.
Avantage second : la souveraineté. Si votre équipe transporte des données clients soumises à la loi sénégalaise 2008-12 ou aux textes équivalents en Côte d’Ivoire, héberger le coordinateur à Dakar (sur un VPS Sonatel, Atlas, ou un OVH/Scaleway en Europe selon votre choix) limite la surface juridique aux seuls textes africains et européens.
Étape 2 — Préparer le VPS Ubuntu 24.04 LTS
Provisionnez un VPS basique : 1 vCPU, 1 Go RAM, 20 Go SSD suffisent pour 50 utilisateurs. À partir de janvier 2026, Ubuntu 24.04 LTS « Noble Numbat » est la cible recommandée (support jusqu’en avril 2029).
ssh root@vps.exemple.sn
apt update && apt upgrade -y
apt install -y ufw curl gnupg ca-certificates
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 3478/udp # STUN, traversée NAT
ufw enable
Sortie attendue : Firewall is active and enabled on system startup. Vérifiez que vous gardez bien votre session SSH active avant de fermer le terminal — si vous oubliez d’autoriser le port 22, vous serez bloqué dehors.
Étape 3 — Installer Headscale en binaire officiel
La version stable courante en janvier 2026 est Headscale 0.26.x (vérifiez sur github.com/juanfont/headscale/releases avant d’exécuter — le numéro évolue). Téléchargez le .deb officiel, c’est le moyen le plus propre.
HS_VER=0.26.1
ARCH=amd64
curl -L -o /tmp/headscale.deb \
https://github.com/juanfont/headscale/releases/download/v${HS_VER}/headscale_${HS_VER}_linux_${ARCH}.deb
dpkg -i /tmp/headscale.deb
systemctl status headscale --no-pager
Ce que vous devez voir : Active: active (running). Le service tourne, mais sur le port 8080 en HTTP — il faut maintenant le mettre derrière Caddy en HTTPS.
Étape 4 — Configurer Headscale (server_url et bases)
Éditez /etc/headscale/config.yaml. Les trois champs critiques sont server_url (URL publique HTTPS), listen_addr (interne 127.0.0.1) et noise.private_key_path (généré automatiquement au premier démarrage).
# /etc/headscale/config.yaml — extrait
server_url: https://hs.exemple.sn
listen_addr: 127.0.0.1:8080
metrics_listen_addr: 127.0.0.1:9090
private_key_path: /var/lib/headscale/private.key
noise:
private_key_path: /var/lib/headscale/noise_private.key
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
ip_prefixes:
- 100.64.0.0/10
- fd7a:115c:a1e0::/48
systemctl restart headscale
journalctl -u headscale -n 30 --no-pager
Cherchez la ligne listening and serving HTTP on 127.0.0.1:8080. Si vous voyez une erreur de DB, vérifiez que /var/lib/headscale appartient à l’utilisateur headscale.
Étape 5 — Pointer le DNS et installer Caddy
Chez votre registrar (Sonatel pour .sn, Africa Registry, OVH, etc.), créez un enregistrement A : hs.exemple.sn → IP publique du VPS. Attendez 2–5 minutes la propagation, vérifiez avec dig hs.exemple.sn +short.
apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \
gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \
tee /etc/apt/sources.list.d/caddy-stable.list
apt update
apt install -y caddy
caddy version # doit afficher v2.8.x ou supérieur
Ce que vous devez voir : v2.8.4 h1:.... Caddy gère automatiquement les certificats Let’s Encrypt — c’est exactement pourquoi on le préfère à Nginx pour ce cas.
Étape 6 — Caddyfile reverse proxy avec HTTPS automatique
Remplacez /etc/caddy/Caddyfile par :
hs.exemple.sn {
encode zstd gzip
reverse_proxy 127.0.0.1:8080
log {
output file /var/log/caddy/headscale.log
format json
}
}
caddy validate --config /etc/caddy/Caddyfile
systemctl reload caddy
journalctl -u caddy -n 20 --no-pager
Cherchez certificate obtained successfully et serving initial configuration. Testez curl -I https://hs.exemple.sn/health — vous devez recevoir HTTP/2 200 et un certificat Let’s Encrypt valide ~ 90 jours, renouvelé automatiquement par Caddy.
Étape 7 — Créer un utilisateur et générer une pre-auth key
L’utilisateur Headscale est un namespace logique (souvent un nom d’équipe). Une pre-auth key permet d’enrôler une machine sans interaction navigateur — pratique pour les VPS et serveurs sans GUI.
headscale users create equipe-dakar
headscale users list
# Sortie attendue :
# ID | Name | Created
# 1 | equipe-dakar | 2026-01-15 10:32:11
headscale preauthkeys create --user equipe-dakar --reusable --expiration 24h
# Sortie : la clé apparaît, copiez-la (elle ressemble à 7b1a...c2)
Stockez cette clé dans un gestionnaire de mots de passe (Bitwarden self-hosted, KeePass) — ne la collez jamais dans Slack ou WhatsApp. Une pre-auth key qui fuit, c’est un accès complet au mesh.
Étape 8 — Connecter le premier client (Linux puis téléphone)
Sur un poste Linux à Abidjan :
curl -fsSL https://tailscale.com/install.sh | sh
tailscale up --login-server=https://hs.exemple.sn \
--auth-key=tskey-auth-XXXX
tailscale status
# Sortie : la machine apparaît avec une IP 100.x.y.z
Sur Android/iOS, installez l’app officielle Tailscale, puis dans Paramètres → Comptes → utilisez « Use a custom coordination server » et collez https://hs.exemple.sn. Connectez-vous avec la pre-auth key. La machine reçoit son IP 100.64/10 et peut pinger les autres nœuds du mesh.
# Tester la connectivité depuis Dakar vers Cotonou
ping -c 3 100.64.0.2
# 64 bytes from 100.64.0.2: icmp_seq=1 ttl=64 time=42.1 ms
42 ms entre Dakar et Cotonou via votre VPS de coordination, c’est typique. Le trafic transite directement entre les nœuds (peer-to-peer), pas via le VPS — Headscale ne fait que la coordination des clés.
Étape 9 — Backup, monitoring et coûts
La SQLite Headscale est un fichier unique : sauvegardez-la chaque nuit avec un cron + rclone vers un S3 compatible (Wasabi, Backblaze B2, ou un MinIO auto-hébergé).
# /etc/cron.daily/backup-headscale
#!/bin/bash
DATE=$(date +%Y%m%d)
sqlite3 /var/lib/headscale/db.sqlite ".backup /tmp/hs-$DATE.db"
rclone copy /tmp/hs-$DATE.db wasabi:backups-headscale/
rm /tmp/hs-$DATE.db
Coût mensuel total typique : VPS 1 vCPU/1 Go ≈ 3 500–6 000 FCFA, domaine .sn ≈ 1 250 FCFA/mois lissé, stockage backup ≈ 500 FCFA. Total ≈ 6 000 FCFA/mois pour servir 50 utilisateurs, contre 200 000 FCFA/mois en Tailscale Business — économies annuelles environ 2,3 millions FCFA.
À lire ensuite, lisez notre tutoriel Astro 5 si vous voulez héberger un portail interne ultra-rapide accessible uniquement via le mesh Headscale, et notre guide LinkedIn B2B pour vendre cette prestation d’auto-hébergement aux PME de votre ville.
Étape 10 — ACL et politique d’accès par groupe
Par défaut, tous les nœuds peuvent se parler. Pour un usage entreprise, vous voulez restreindre : les commerciaux n’ont pas besoin d’accéder au serveur de base de données, les développeurs n’ont pas besoin de la GPO RH. Headscale supporte un fichier de politique JSON-like inspiré de Tailscale.
# /etc/headscale/policy.hujson
{
"groups": {
"group:dev": ["alice@equipe-dakar", "moussa@equipe-dakar"],
"group:sales": ["fatou@equipe-dakar"],
"group:admin": ["mamadou@equipe-dakar"]
},
"acls": [
{ "action": "accept", "src": ["group:admin"], "dst": ["*:*"] },
{ "action": "accept", "src": ["group:dev"], "dst": ["tag:db:5432","tag:web:443"] },
{ "action": "accept", "src": ["group:sales"], "dst": ["tag:crm:443"] }
]
}
headscale policy set -f /etc/headscale/policy.hujson
headscale policy check -f /etc/headscale/policy.hujson
Résultat type : policy is valid. Toute erreur de syntaxe affiche la ligne fautive — corrigez avant de pousser, sinon le mesh continue avec l’ancienne politique. Ce mécanisme évite la fuite latérale entre équipes : un commercial dont le poste est compromis ne peut pas atteindre la base de données.