VPNSmith
Outil gratuit - serveur Headscale

Générateur de configuration Headscale

Saisissez votre domaine, choisissez Docker ou le paquet .deb et la gestion du HTTPS : le générateur écrit config.yaml, le fichier compose ou le script d'installation, le fichier du reverse proxy, une politique d'exit node facultative et les commandes pour créer votre premier utilisateur et connecter un appareil. Construit à partir des fichiers officiels de Headscale 0.29.5. Rien ne quitte votre navigateur.

Tout est généré dans votre navigateur. Rien n'est envoyé ni stocké.

Un nom DNS dont l'enregistrement A (et AAAA) pointe vers le VPS, par exemple headscale.example.com.

Les appareils deviennent nom.domaine-de-base. Doit être différent du domaine ci-dessus ; il n'a pas besoin d'exister publiquement.

Créé avec headscale users create. Sert aussi de propriétaire du tag dans la politique d'exit node.

Utilisé par certbot ou Headscale pour les avis d'expiration. Caddy fonctionne sans.

Méthode d'installation
HTTPS

Caddy est le chemin le plus court. Choisissez nginx s'il tourne déjà sur le serveur, le TLS intégré si le VPS ne fait tourner que Headscale.

DNS amont pour MagicDNS
Options
  • Créez l'enregistrement DNS du domaine avant de démarrer : la demande de certificat échoue si le nom ne pointe pas encore vers le VPS.

Généré pour https://headscale.example.com · Headscale 0.29.5 · 6 fichiers

/opt/headscale/config/config.yaml
---
# Headscale 0.29.5: /etc/headscale/config.yaml
server_url: https://headscale.example.com
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090
grpc_listen_addr: 127.0.0.1:50443
grpc_allow_insecure: false
trusted_proxies: []
noise:
  private_key_path: /var/lib/headscale/noise_private.key
prefixes:
  v4: 100.64.0.0/10
  v6: fd7a:115c:a1e0::/48
  allocation: sequential
derp:
  server:
    enabled: false
    region_id: 999
    region_code: "headscale"
    region_name: "Headscale Embedded DERP"
    verify_clients: true
    stun_listen_addr: "0.0.0.0:3478"
    private_key_path: /var/lib/headscale/derp_server_private.key
    automatically_add_embedded_derp_region: true
  urls:
    - https://controlplane.tailscale.com/derpmap/default
  paths: []
  auto_update_enabled: true
  update_frequency: 3h
disable_check_updates: false
node:
  expiry: 0
  ephemeral:
    inactivity_timeout: 30m
database:
  type: sqlite
  sqlite:
    path: /var/lib/headscale/db.sqlite
    write_ahead_log: true
    wal_autocheckpoint: 1000
acme_url: https://acme-v02.api.letsencrypt.org/directory
acme_email: ""
tls_letsencrypt_hostname: ""
tls_letsencrypt_cache_dir: /var/lib/headscale/cache
tls_letsencrypt_challenge_type: HTTP-01
tls_letsencrypt_listen: ":http"
tls_cert_path: ""
tls_key_path: ""
log:
  level: info
  format: text
policy:
  mode: file
  path: "/etc/headscale/policy.json"
dns:
  magic_dns: true
  base_domain: ts.example.com
  override_local_dns: true
  nameservers:
    global:
      - 1.1.1.1
      - 1.0.0.1
      - 2606:4700:4700::1111
      - 2606:4700:4700::1001
    split: {}
  search_domains: []
  extra_records: []
unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"
logtail:
  enabled: false
taildrop:
  enabled: true
/opt/headscale/docker-compose.yaml
services:
  headscale:
    image: docker.io/headscale/headscale:0.29.5
    container_name: headscale
    restart: unless-stopped
    read_only: true
    tmpfs:
      - /var/run/headscale
    ports:
      - "127.0.0.1:8080:8080"
      - "127.0.0.1:9090:9090"
    volumes:
      - /opt/headscale/config:/etc/headscale:ro
      - /opt/headscale/lib:/var/lib/headscale
    command: serve
    healthcheck:
      test: ["CMD", "headscale", "health"]

  caddy:
    image: docker.io/library/caddy:2
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - /opt/headscale/Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - headscale

volumes:
  caddy_data:
  caddy_config:
/opt/headscale/Caddyfile
http://headscale.example.com {
	# Tailscale captive portal detection
	handle /generate_204 {
		respond 204
	}

	handle * {
		redir https://{host}{uri}
	}
}

headscale.example.com {
	reverse_proxy headscale:8080 {
		header_up True-Client-IP {remote_host}
		header_up X-Real-IP {remote_host}
	}
}
/opt/headscale/config/policy.json
{
  "tagOwners": {
    "tag:exit": [
      "admin@"
    ]
  },
  "autoApprovers": {
    "exitNode": [
      "tag:exit"
    ]
  }
}
setup-headscale.sh
#!/usr/bin/env bash
set -euo pipefail

# 1. Installer Docker s'il manque (script officiel)
command -v docker >/dev/null || curl -fsSL https://get.docker.com | sudo sh

# 2. Dossiers pour la configuration et les données
sudo mkdir -p /opt/headscale/config /opt/headscale/lib
cd /opt/headscale

# 3. Enregistrez d'abord les fichiers générés à ces emplacements
for f in config/config.yaml docker-compose.yaml Caddyfile config/policy.json; do
  [ -f "$f" ] || { echo "Missing /opt/headscale/$f"; exit 1; }
done

# 4. Démarrer Headscale
sudo docker compose up -d
sleep 5

# 5. Vérification : doit afficher un état de santé en JSON
curl -fsS http://127.0.0.1:8080/health
first-steps.sh
# Créer le premier utilisateur
sudo docker exec headscale headscale users create admin

# Relever l'identifiant numérique de l'utilisateur
sudo docker exec headscale headscale users list

# Créer une clé pré-authentifiée (valable 1 heure, usage unique par défaut)
sudo docker exec headscale headscale preauthkeys create --user <USER_ID>

# Sur chaque appareil : se connecter à votre serveur Headscale
sudo tailscale up --login-server https://headscale.example.com --authkey <YOUR_AUTH_KEY>

# Sur le VPS exit node : se connecter avec le tag pour être auto-approuvé
sudo tailscale up --login-server https://headscale.example.com --authkey <YOUR_AUTH_KEY> \
  --advertise-exit-node --advertise-tags=tag:exit

# Après modification de policy.json : recharger Headscale
sudo docker kill --signal=HUP headscale

# Connexion par le navigateur : approuver l'appareil avec l'Auth ID qu'il affiche
sudo docker exec headscale headscale auth register --user admin --auth-id <AUTH_ID>

# Lister les appareils connectés
sudo docker exec headscale headscale nodes list

Headscale a besoin d'un serveur toujours en ligne

Un petit VPS avec IPv4 et IPv6 publiques exécute ces fichiers tels quels, et la même machine peut servir d'exit node à votre tailnet.

Lien affilié : nous pouvons toucher une commission, sans surcoût pour vous. Le générateur reste gratuit et n'en dépend pas.

Voir le VPS Contabo

Ce que font les fichiers générés

Headscale est le remplaçant open source du serveur de contrôle de Tailscale : vos appareils gardent les applications Tailscale officielles, mais se connectent à votre propre serveur avec --login-server. Il lui faut trois choses : une adresse HTTPS publique sur le port 443 identique à server_url, un base_domain MagicDNS différent de cette adresse, et un reverse proxy qui laisse passer les upgrades WebSocket si Headscale ne gère pas lui-même le TLS.

Le config.yaml reprend le fichier d'exemple complet de la version 0.29.5 avec vos valeurs : toutes les clés sont présentes et rien ne dépend d'une valeur par défaut non documentée. Sous Docker, le conteneur écoute sur 0.0.0.0 dans son propre réseau et les ports ne sont publiés que sur 127.0.0.1, sauf 80 et 443 quand Headscale termine le TLS. Derrière un reverse proxy sur la même machine, trusted_proxies vaut localhost pour que les vraies IP clientes apparaissent dans les journaux.

Plusieurs commandes ont changé dans les dernières versions, ce qui fait échouer beaucoup de tutoriels : les clés pré-authentifiées se créent désormais avec l'identifiant numérique de l'utilisateur (affiché par headscale users list), et un appareil connecté par le navigateur s'approuve avec headscale auth register et son Auth ID. Le bloc des premières étapes utilise la syntaxe 0.29.

Caddy, nginx ou TLS intégré ?

Trois façons de servir Headscale en HTTPS, toutes documentées par le projet. Le bon choix dépend de ce qui tourne déjà sur le serveur.

HTTPS géré parCertificatIdéal quandAttention
Caddy (reverse proxy)Automatique, renouvelé par CaddyVous voulez l'installation la plus courte, ou d'autres sites sur le même VPSLes ports 80 et 443 doivent arriver sur Caddy ; le WebSocket fonctionne sans ligne de plus
nginx (reverse proxy)certbot, renouvelé par son timernginx sert déjà d'autres sites sur la machineLes en-têtes Upgrade et Connection sont obligatoires, sinon les clients ne se connectent jamais
Let's Encrypt intégré à HeadscaleAutomatique, renouvelé par HeadscaleLe VPS ne fait tourner que HeadscaleHeadscale prend les ports 80 et 443 pour lui seul ; aucun autre service web sur cette IP

Questions fréquentes

Quel est le config.yaml minimal pour Headscale ?
Headscale lit /etc/headscale/config.yaml. Les valeurs à changer sont server_url (votre adresse HTTPS publique), listen_addr et dns.base_domain, qui doit être un domaine différent de celui de server_url. Le départ le plus sûr est le fichier d'exemple de votre version exacte avec ces valeurs modifiées, ce que produit ce générateur, car des clés changent de nom d'une version à l'autre.
Pourquoi tailscale up reste bloqué ou échoue avec mon serveur Headscale ?
Le plus souvent, le reverse proxy ne transmet pas l'upgrade WebSocket (nginx sans les en-têtes Upgrade et Connection), server_url ne correspond pas à l'adresse utilisée par les clients, ou le certificat n'est pas reconnu. Testez curl https://votre-domaine/health depuis l'extérieur du serveur, puis lisez les journaux de Headscale. Un port autre que 443 est possible, mais le client Tailscale suppose 443 dans certains cas.
Comment créer une clé pré-authentifiée dans Headscale 0.29 ?
Créez un utilisateur avec headscale users create <nom>, relevez son identifiant numérique avec headscale users list, puis lancez headscale preauthkeys create --user <ID>. Par défaut la clé est valable une heure et ne sert qu'une fois. Sur l'appareil : tailscale up --login-server https://votre-domaine --authkey <clé>.
Ai-je besoin du serveur DERP embarqué ?
Non. Par défaut, Headscale fournit aux clients les relais DERP publics de Tailscale, utilisés seulement quand une connexion directe est impossible. Activez le DERP embarqué si vous voulez des relais sous votre contrôle : il faut ouvrir l'UDP 3478 et indiquer l'IPv4 publique (et l'IPv6 s'il y en a une) du serveur.
Quelle taille de VPS pour Headscale ?
Très peu : le serveur de contrôle ne fait que coordonner les clés et les routes, le trafic passe directement entre les appareils. Les plus petites offres suffisent pour un foyer ou une petite équipe. L'essentiel est une IPv4 publique, idéalement une IPv6, et un hébergeur qui laisse ouverts les ports 80, 443 et 3478. La même machine peut aussi servir d'exit node.