all repos — blog @ main

Code and content for 5ika.ch

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.