content/posts/un-vpn-facile.md (view raw)
1---
2Title: Mettre en place un VPN facilement
3Date: 2026-05-05
4---
5
6Pour mon entreprise, je gère un ensemble de serveurs hébergeant nos outils internes, nos instances de test ainsi que certaines instances de production.
7C'est un job à plein temps que de gérer ces serveurs et, comme la plupart des services n'ont pas énormément d'utilisateurs, c'est souvent exagérément long de mettre en place des points d'accès sécurisés voir de faire les configurations minimales.
8
9L'an passé, j'ai passé pas mal d'heures à configurer des interfaces [Wireguard](https://www.wireguard.com/) sur chaque serveur. J'adore Wireguard pour son côté minimal et bas niveau mais avec le nombre de serveurs et d'utilisateurs augmentant, ça devient rapidement galère de gérer les configs sur chaque serveur.
10
11Après quelques recherches, je suis tombé sur [Tailscale](https://tailscale.com/) et son alter-ego Open-Source auto-hébergeable [Headscale](https://headscale.net/). Ce système repose sur Wireguard mais s'occupe de toute la partie config redondante tout en ajoutant des fonctionnalités supplémentaires: DNS automatique des nodes connectés, gestion facilité du SSH, règles ACL, file sharing et [d'autres encores](https://headscale.net/stable/about/features/).
12
13Cependant, la doc de Headscale est plutôt limitée et celle de Tailscale me perd rapidement. Je profite donc de cet article pour documenter les quelques étapes utiles pour mettre en place un réseau privé Open-Source en 10 minutes.
14
15## Mise en place du control plane
16
17Headscale est à installer sur un serveur accessible en ligne.
18Soit [directement sur la machine](https://headscale.net/stable/setup/install/official/#using-standalone-binaries-advanced), soit en utilisant un [container Docker](https://headscale.net/stable/setup/install/container/).
19
20Pour la méthode Docker, le programme `headscale` doit être lancé avec la commande suivante:
21
22```bash
23docker exec -it headscale headscale
24```
25
26Ce qui n'est pas très pratique donc je préfère ajouter un alias au niveau de Bash:
27
28```bash
29alias headscale=`docker exec -it headscale headscale`
30```
31
32De mon côté, j'utilise généralement Docker Compose avec une auto-config Traefik:
33
34```yaml
35services:
36 headscale:
37 image: headscale/headscale:stable
38 container_name: headscale
39 restart: unless-stopped
40 volumes:
41 - ./config:/etc/headscale:ro
42 - ./lib:/var/lib/headscale
43 command: serve
44 healthcheck:
45 test: ["CMD", "headscale", "health"]
46 interval: 10s
47 timeout: 5s
48 retries: 3
49 labels:
50 - traefik.enable=true
51 - traefik.http.routers.headscale.rule=Host(`headscale.myhost.ch`)
52 - traefik.http.routers.headscale.entrypoints=websecure
53 - traefik.http.services.headscale.loadbalancer.server.port=8080
54 - traefik.http.routers.headscale.tls=true
55 - traefik.http.routers.headscale.tls.certresolver=letsencrypt
56```
57
58Ensuite, on récupère la base de configuration et on l'édite. Elle est bien documentée et facile à adapter.
59
60```bash
61wget -O config/config.yaml https://github.com/juanfont/headscale/blob/main/config-example.yaml
62$EDITOR config/config.yaml
63```
64
65Afin de configuer les ACL, il faut notamment modifier les lignes `policy.path` pour adapter comme suit:
66
67```yaml
68policy:
69 path: "/etc/headscale/acl.hujson"
70```
71
72Et on crée le fichier `acl.hujson` dans le dossier `config/` avec le contenu suivant (à adapter selon les besoins):
73
74```json
75{
76 "acls": [
77 {
78 "action": "accept",
79 "src": ["*"],
80 "dst": ["*:*"]
81 }
82 ],
83 "ssh": [
84 {
85 "action": "accept",
86 "src": ["autogroup:member"],
87 "dst": ["autogroup:member"],
88 "users": ["root"]
89 }
90 ]
91}
92```
93
94Pour plus d'infos sur la configuration des ACLs, [voir la doc de Tailscale](https://tailscale.com/docs/features/access-control/acls).
95
96Ensuite, on (re)démarre Headscale pour appliquer la nouvelle configuration. Avec Docker Compose: `docker compose up -d`.
97
98## Configuration du client
99
1001. Sur chaque node que l'on veut connecter au VPN, on installe [Tailscale CLI](https://tailscale.com/docs/reference/tailscale-cli).
1012. Sur le serveur, on crée un utilisateur
102```bash
103headscale users create <user>
104```
1053. On génère une *PreAuthKey* pour cette utilisateur
106```bash
107headscale preauthkeys create --user <user>
108```
1094. Sur la machine cliente, on se connecte en utilisant la PreAuthKey
110```bash
111tailscale up --login-server https://headscale.myhost.ch --authkey <preAuthKey>
112```
113
114Pour tester que l'on obtient bien une IP dans le VPN:
115
116```bash
117tailscale status
118```
119
120Une fois que nous avons au moins deux nodes dans le réseau, on peut faire un ping entre les deux pour tester le lien. Grâce au [MagicDNS](https://tailscale.com/docs/features/magicdns) fourni par Headscale, on peut utiliser le hostname de chaque client pour le contacter.
121Par exemple, si un client est connecté avec une machine dans le hostname est `deer`, on peut faire `ping deer` depuis un autre node pour l'atteindre.
122
123## Notes de fin
124
125Ces quelques commandes permettent de créer rapidement un réseau VPN. Je passe sur les configurations nécessaires pour rendre accessible le Headscale depuis le Web car cela dépend fortement du cas d'usage. L'utilisation de Traefik Proxy ou d'un Caddy server rend ça plutôt simple.
126
127Dès que l'on fait grandir le réseau, il devient assez vite nécessaire de mettre en place des ACL un peu réfléchies.
128
129Pour voir toutes les possibilités offertes, [cette page](https://headscale.net/stable/about/features/) est une bonne référence.