tuto headscale vpn self hosted
  • 8 mai 2025
  • ComputaSYS
  • 0


I. Présentation

Vous appréciez Tailscale, la solution de VPN Mesh basée sur WireGuard ? Alors, vous allez probablement apprécier Headscale ! Comme vous le savez, l’utilisation de Tailscale implique de s’appuyer sur les serveurs de Tailscale pour distribuer les informations aux clients connectés. Pour ceux qui veulent avoir une maitrise complète de l’infrastructure, et ne pas dépendre de ce tiers, sachez qu’une solution existe : Headscale.

Ce projet open source permet de ne pas utiliser l’infrastructure Tailscale puisque Headscale vous permet d’auto-héberger votre propre serveur de contrôle Tailscale. Ainsi, vous continuez à utiliser les applications Tailscale officielles, mais c’est votre serveur Headscale qui sera sollicité. Dans tous les cas, des tunnels WireGuard sont utilisés et le trafic réseau ne passe pas par le serveur Headscale (il sert à distribuer les clés, les routes et les ACLs).

Dans ce tutoriel, nous allons apprendre à déployer la solution Headscale sur un serveur Linux (Debian, pour ma part), sans utiliser Docker. C’est une précision importante, car les deux types de déploiement sont supportés : avec ou sans Docker. Cette solution peut être utilisée dans un cadre personnel ou professionnel, selon les besoins.

L’exemple ci-dessous illustre le besoin suivant : vous souhaitez accéder à distance, de façon sécurisée, à votre réseau et à vos équipements. Vous pouvez installer Tailscale sur vos appareils (ordinateurs, smartphones, tablettes, etc.) et accéder à ces équipements via le nœud Tailscale “Gateway” (car il va diffuser une route). Vous pourriez aussi interconnecter deux réseaux, tout en permettant les accès depuis des équipements nomades. La sécurité sera assurée par les ACL qui vont permettre de déterminer qui peut communiquer avec qui.

Dans le cadre de cette démonstration, une machine sous Debian, nommée SRV-HEADSCALE sera utilisée. Il s’agit d’un serveur virtuel dans le Cloud Azure : le serveur Headscale doit être accessible à tout moment pour que le service soit opérationnel, ce choix me semble donc judicieux. Vous pouvez prendre un VPS chez un autre fournisseur, par exemple. Le service sera accessible via le domaine suivant : headscale.it-connect.cloud.

Si vous souhaitez en savoir plus sur le potentiel de Headscale, je vous renvoie vers le tutoriel Tailscale :

II. Pourquoi choisir Headscale à la place de Tailscale ?

Headscale est une implémentation open source du serveur de coordination Tailscale, qui permet de déployer un réseau mesh basé sur WireGuard sans dépendre de l’infrastructure Cloud de Tailscale.

Le principal avantage de Headscale réside dans le contrôle total qu’il offre à l’administrateur : les données de configuration, les clés et les échanges d’informations ne transitent pas par des serveurs tiers. Le fait de se passer de l’infrastructure de Tailscale offre aussi un avantage : vous n’avez pas d’abonnement à payer (même si, je vous rappelle, il y a une version gratuite de Tailscale).

Pour autant, il n’y a pas que des avantages à utiliser Headscale. En effet, contrairement à Tailscale, qui propose une interface utilisateur aboutie et complète, un système de gestion des identités (SSO) et un support technique, Headscale nécessite de tout configurer soi-même, avec des fichiers de configuration. À noter qu’il existe tout de même des projets tiers pour doter Headscale d’une interface de gestion web. Plusieurs projets sont référencés sur le site de Headscale, y compris Headscale-UI.

III. Installation du reverse proxy Nginx

Le serveur Headscale doit être accessible en HTTPS avec un certificat TLS valide pour fonctionner. Il prend en charge, nativement, l’obtention d’un certificat via Let’s Encrypt à condition que la configuration du serveur soit compatible. Si vous avez déjà un reverse proxy (Nginx, HAProxy, Traefik, etc.), vous pouvez l’utiliser pour publier Headscale.

Pour ma part, j’ai préféré installer un serveur Nginx sur le même serveur que Headscale pour gérer la publication de l’application. Ainsi, la première étape suite à l’installation du serveur, sera d’installer le paquet nginx :

sudo apt update -y
sudo apt install nginx -y
sudo systemctl enable nginx

Puis, nous allons créer un fichier de configuration Headscale pour déclarer les paramètres du reverse proxy :

sudo nano /etc/nginx/sites-available/headscale.it-connect.cloud

Indiquez le code suivant, en veillant à remplacer le nom de domaine. Les requêtes à destination de https://headscale.it-connect.cloud seront relayées vers http://127.0.0.1:8080, ce qui correspond à l’application Headscale en local.

server {
listen 443 ssl;
server_name headscale.it-connect.cloud;

ssl_certificate /etc/letsencrypt/live/headscale.it-connect.cloud/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/headscale.it-connect.cloud/privkey.pem;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;

location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;

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;
}

}

upstream headscale.it-connect.cloud {
server 127.0.0.1:8080;
}

Enregistrez et fermez le fichier. Vérifiez la syntaxe du fichier de configuration via cette commande :

sudo nginx -t

Si vous n’avez pas d’erreur, vous pouvez passer à la suite.

Nous allons installer Certbot pour Nginx afin de demander un certificat via Let’s Encrypt.

sudo apt install certbot python3-certbot-nginx -y

Puis, nous demandons un certificat pour le domaine headscale.it-connect.cloud. Le certificat et la clé privée seront déposés dans le répertoire suivant : /etc/letsencrypt/live/headscale.it-connect.cloud/.

sudo certbot –nginx -d headscale.it-connect.cloud

Pour en finir avec la mise en place du reverse proxy, nous activons le nouveau site configuré précédemment et nous désactivons le site par défaut :

sudo ln -s /etc/nginx/sites-available/headscale.it-connect.cloud /etc/nginx/sites-enabled/headscale.it-connect.cloud
sudo rm /etc/nginx/sites-enabled/default

Désormais, nous allons évoquer l’installation de Headscale !

IV. Mise en œuvre de Headscale sur Linux

L’installation sera effectuée sur une machine sous Debian 12 (dernière version stable actuelle). Au-delà de l’installation, nous verrons comment configurer Headscale : création d’un utilisateur, ajout de machines au réseau, création d’ACL, etc.

A. Installation de Headscale

Il y a un paquet DEB prêt à l’emploi que nous pouvons utiliser pour installer Headscale sur Debian ou Ubuntu. Telle que le suggère la documentation officielle, nous allons déclarer 2 variables pour spécifier la version à installer et le type d’architecture. Pour obtenir le numéro de version de la version la plus récente, consultez cette page.

Voici comment télécharger Headscale 0.25.1 sur une machine 64 bits (AMD64) :

HEADSCALE_VERSION=”0.25.1″
HEADSCALE_ARCH=”amd64″

wget –output-document=headscale.deb \
“https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_${HEADSCALE_ARCH}.deb”

Une fois le paquet DEB téléchargé en local sur votre serveur, lancez l’installation :

sudo apt install ./headscale.deb

Cette opération est rapide et désormais, nous allons pouvoir effectuer la configuration.

B. Configuration de Headscale

Sur votre serveur, éditez le fichier de configuration config.yaml correspondant à la configuration de Headscale.

sudo nano /etc/headscale/config.yaml

Nous n’allons pas modifier tous les paramètres, mais uniquement ceux indispensables pour démarrer. Les ACL se déclarent dans un autre fichier. Voici 3 paramètres à modifier :

server_url : l’URL complète de votre serveur Headscale.

listen_addr : adresse IP sur laquelle écoute le service, il s’agit ici de la valeur recommandée pour la production.

base_domain : le nom de domaine que vous souhaitez utiliser pour le service MagicDNS.

server_url: https://headscale.it-connect.cloud:443
listen_addr: 0.0.0.0:8080
dns:
base_domain: it-connect.cloud

Il y a d’autres paramètres, notamment pour utiliser PostgreSQL à la place de SQLite, ou encore pour personnaliser le sous-réseau utilisé pour les tunnels WireGuard. Vous pouvez aussi créer des enregistrements DNS personnalisés. Je vous invite à prendre le temps de parcourir le fichier.

Enregistrez la configuration puis fermez le fichier. Activez le démarrage automatique et lancez Headscale :

sudo systemctl enable –now headscale
sudo systemctl status headscale

C. Créer un utilisateur

Headscale est actif sur notre serveur. Nous devons maintenant commencer à exploiter l’application, ce qui implique de réaliser deux étapes :

Créer un compte utilisateur

Créer un appareil (nœud) et l’associer à notre utilisateur

Si vous envisagez d’utiliser certains nœuds comme passerelle vers des réseaux, vous pouvez créer un utilisateur gateway et lui associer ces nœuds. Ensuite, créez des utilisateurs nominatifs pour les terminaux tels que les smartphones, les PC, etc.

Voici comment créer un utilisateur nommé florian.burnel :

headscale users create florian.burnel

Vous pouvez ensuite lister vos utilisateurs :

sudo headscale users list

L’utilisateur est bien créé !

D. Enregistrer ses premiers appareils

Pour enregistrer des appareils, vous avez deux options :

Créer une clé de préauthentification sur le serveur Headscale et saisir la clé sur un appareil via le client Tailscale.

Connecter le client Tailscale à Headscale pour effectuer une demande de connexion et approuver la connexion via Headscale (méthode obligatoire pour Android, à ce jour).

Commençons par tester la première méthode en rattachant cette clé à l’utilisateur créé précédemment.

sudo headscale preauthkeys create –user florian.burnel

Cette commande retourne la clé suivante : ae2edcca9b1aca445ce3a9c7748ff3c43e96d1613ab941cd. À présent, vous devez basculer sur la machine qui doit rejoindre votre réseau Headscale et procéder à l’installation du client Tailscale.

Une fois le client Tailscale installé, ouvrez une console et exécutez la commande suivante. Vous devez remplacer l’adresse du serveur et la clé d’authentification.

tailscale up –login-server https://headscale.it-connect.cloud –authkey ae2edcca9b1aca445ce3a9c7748ff3c43e96d1613ab941cd

Voilà, vous venez d’ajouter votre premier nœud à votre réseau ! Vous pouvez le vérifier dès maintenant via cette commande :

sudo headscale nodes list

Nous pouvons voir qu’il s’agit d’un nœud persistant, sans date d’expiration.

L’opération doit être répétée pour les autres nœuds à connecter. Néanmoins, grâce à la distribution des routes, vous n’êtes pas obligé de déployer le client Tailscale sur tous les appareils d’un réseau.

Évoquons l’ajout d’un client Android, car la procédure est légèrement différente puisqu’elle repose sur la seconde méthode.

L’application Tailscale officielle doit être installée. Il convient d’accéder à la partie “Accounts” pour sélectionner l’option nommée “Usage an alternate server” à partir du menu (trois points verticaux).

Vous devez renseigner l’adresse URL de votre serveur Headscale. Ici, je précise donc https://headscale.it-connect.cloud.

Sur le smartphone, la commande spécifiée ci-dessous s’affiche et elle doit être exécutée sur le serveur Headscale pour effectuer l’inscription de ce nouveau client. Il s’agit d’une tentative d’inscription initiée depuis le smartphone et qui doit être approuvée.

sudo headscale nodes register –user florian.burnel -key

Sur le serveur Headscale, vous pouvez lister les clients pour vérifier la présence d’un nouvel appareil :

sudo headscale nodes list

Le smartphone est bien connecté au réseau et il a une visibilité sur les autres nœuds.

Ici, l’appareil est remonté avec le nom localhost, ce qui est loin d’être idéal… Il est possible de changer le nom et ce cas me donne l’occasion de vous expliquer comment procéder. Dans l’exemple ci-dessous, le nœud avec l’ID 3 est ciblé et sera renommé en tant que smartphone-flo.

sudo headscale nodes rename smartphone-flo -i 3

Ensuite, le nom dans la colonne Name sera renommé.

Depuis le nœud sous Windows, il est tout à fait possible d’effectuer un ping du smartphone via son nouveau nom. Bien entendu, les deux appareils doivent être connectés au réseau Headscale pour que cela fonctionne.

E. Ajouter une route

Actuellement, nos appareils peuvent communiquer entre eux grâce aux tunnels WireGuard et à notre serveur Headscale. Néanmoins, il n’est pas possible d’atteindre une machine située sur le même réseau que l’un des nœuds. C’est normal, il s’agit du comportement par défaut.

Nous allons configurer le nœud PC-FLO pour qu’il donne accès au réseau 192.168.1.0/24 sur lequel il est connecté. Ceci vous montre qu’un simple poste de travail peut faire office de passerelle vers un réseau local (à condition qu’il soit allumé). Vous pouvez aussi utiliser un hôte dédié à cet usage, notamment une machine légère sous Linux ou une machine virtuelle.

Note : le routage au travers d’une machine Windows fonctionnera nativement. Cependant, si vous utilisez une machine Linux, vous devez activer le routage tel que expliqué sur cette page de la documentation officielle.

Sur la machine connectée au réseau à diffuser, il est nécessaire d’exécuter la commande suivante :

tailscale set –advertise-routes 192.168.1.0/24

L’information sera remontée auprès du serveur Headscale. Vous pouvez vous en assurer en listant les routes :

sudo headscale route list

La nouvelle route est bien visible. Cependant, elle n’est pas activée, car elle doit être approuvée manuellement par l’administrateur (et on ne va pas s’en plaindre). Ainsi, nous ciblons la route par son ID, à savoir le 1.

sudo headscale route enable -r 1

Suite à cette configuration, il m’est possible d’accéder aux machines connectées au réseau 192.168.1.0/24 à distance, via le nœud PC-FLO qui distribue cette route.

F. Gérer les ACL

Pour terminer, nous allons évoquer une notion importante : les ACL, c’est-à-dire les règles d’accès. Grâce à elles, vous pouvez déterminer qui peut communiquer avec qui, car actuellement tout est autorisé.

Vous devez commencer par modifier le fichier de configuration de Headscale :

sudo nano /etc/headscale/config.yaml

Puis, repérez la section policy afin de modifier la directive path. Par défaut, elle est vide. Nous allons ajouter la valeur acl.json puisque nous allons créer le fichier /etc/headscale/acl.json pour décrire nos ACL. Ce qui donne :

policy:
# The mode can be “file” or “database” that defines
# where the ACL policies are stored and read from.
mode: file
# If the mode is set to “file”, the path to a
# HuJSON file containing ACL policies.
path: “acl.json”

Ensuite, créez et éditer le fichier en question :

sudo nano /etc/headscale/acl.json

Vous n’avez plus qu’à écrire vos règles d’accès, en vous appuyant sur la documentation de Tailscale parce que le même moteur de règles est repris. Il est possible d’utiliser des groupes et des tags, mais ce n’est pas obligatoire. Vous pouvez appliquer les ACL sur des périphériques ou des utilisateurs : plusieurs approches sont possibles.

L’exemple ci-dessous permet de créer le groupe admins dont l’utilisateur florian.burnel sera membre. Ce groupe sera propriétaire de 2 tags : clients qui sera affecté aux appareils considérés comme des clients et serveurs pour les appareils considérés comme des cibles à administrer. L’idée étant d’autoriser les clients à accéder aux serveurs, sans qu’un client puisse se connecter à un autre client. Les clients pourront aussi accéder au réseau 192.168.1.0/24. Ici, nous ne filtrons pas sur les ports (*), mais il est possible d’appliquer des restrictions différentes selon des groupes.

{
“groups”: {
“group:admins”: [“florian.burnel”]
},
“tagOwners”: {
“tag:clients”: [“group:admins”],
“tag:servers”: [“group:admins”]
},
“acls”: [
{
“action”: “accept”,
“src”: [
“tag:clients”
],
“dst”: [
“tag:servers:*”,
“192.168.1.0/24:*”
]
}
]
}

Au-delà de déclarer les ACL, nous devons, dans notre cas, attribuer les tags aux nœuds. Chaque nœud aura un tag, selon sa fonction. L’exemple ci-dessous sert à affecter le tag clients à la machine dont l’ID est 3. Veillez à utiliser le format tag:.

sudo headscale nodes tags -i 3 -t tag:clients

Il convient alors de redémarrer Headscale :

sudo systemctl restart headscale.service

Désormais, grâce à la mise en place de ces règles, il m’est possible de me connecter à distance, à mon réseau et aux appareils qui lui sont connectés, à partir de toutes les machines avec le tag clients.

V. Conclusion

En suivant ce tutoriel, vous devriez être en mesure de mettre en œuvre un VPN Mesh WireGuard grâce à l’utilisation de votre serveur Headscale personnel. Au-delà de la configuration du service en lui-même, veillez à sécuriser votre serveur et à effectuer une maintenance régulière.

Pour aller plus loin, vous pouvez consulter la documentation de Headscale et même celle de Tailscale pour certains aspects.

Ingénieur système et réseau, cofondateur d’IT-Connect et Microsoft MVP “Cloud and Datacenter Management”. Je souhaite partager mon expérience et mes découvertes au travers de mes articles. Généraliste avec une attirance particulière pour les solutions Microsoft et le scripting. Bonne lecture.



Source link

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *