VPNSmith
Strumento gratuito - server Headscale

Generatore di configurazione Headscale

Inserisci il tuo dominio, scegli Docker o il pacchetto .deb e come gestire l'HTTPS: il generatore scrive config.yaml, il file compose o lo script di installazione, il file del reverse proxy, una policy facoltativa per gli exit node e i comandi per creare il primo utente e collegare un dispositivo. Costruito sui file ufficiali di Headscale 0.29.5. Nulla lascia il tuo browser.

Tutto viene generato nel tuo browser. Nulla viene inviato o salvato.

Un nome DNS il cui record A (e AAAA) punta al VPS, per esempio headscale.example.com.

I dispositivi diventano nome.dominio-base. Deve essere diverso dal dominio sopra; non serve che esista pubblicamente.

Creato con headscale users create. È anche il proprietario del tag nella policy degli exit node.

Usata da certbot o Headscale per gli avvisi di scadenza. Caddy funziona senza.

Metodo di installazione
HTTPS

Caddy è la via più breve. Scegli nginx se gira già sul server, il TLS integrato se sul VPS gira solo Headscale.

DNS upstream per MagicDNS
Opzioni
  • Crea il record DNS del dominio prima di avviare: la richiesta del certificato fallisce se il nome non punta ancora al VPS.

Generato per https://headscale.example.com · Headscale 0.29.5 · 6 file

/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. Installare Docker se manca (script ufficiale)
command -v docker >/dev/null || curl -fsSL https://get.docker.com | sudo sh

# 2. Cartelle per configurazione e dati
sudo mkdir -p /opt/headscale/config /opt/headscale/lib
cd /opt/headscale

# 3. Salva prima i file generati in questi percorsi
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. Avviare Headscale
sudo docker compose up -d
sleep 5

# 5. Verifica: deve stampare uno stato di salute in JSON
curl -fsS http://127.0.0.1:8080/health
first-steps.sh
# Creare il primo utente
sudo docker exec headscale headscale users create admin

# Annotare l'ID numerico dell'utente
sudo docker exec headscale headscale users list

# Creare una chiave preautenticata (vale 1 ora, monouso per impostazione predefinita)
sudo docker exec headscale headscale preauthkeys create --user <USER_ID>

# Su ogni dispositivo: accedere al tuo server Headscale
sudo tailscale up --login-server https://headscale.example.com --authkey <YOUR_AUTH_KEY>

# Sul VPS exit node: accedere con il tag per l'approvazione automatica
sudo tailscale up --login-server https://headscale.example.com --authkey <YOUR_AUTH_KEY> \
  --advertise-exit-node --advertise-tags=tag:exit

# Dopo aver modificato policy.json: ricaricare Headscale
sudo docker kill --signal=HUP headscale

# Accesso dal browser: approvare il dispositivo con l'Auth ID che mostra
sudo docker exec headscale headscale auth register --user admin --auth-id <AUTH_ID>

# Elencare i dispositivi collegati
sudo docker exec headscale headscale nodes list

Headscale ha bisogno di un server sempre acceso

Un piccolo VPS con IPv4 e IPv6 pubblici esegue questi file così come sono, e la stessa macchina può essere l'exit node della tua tailnet.

Link di affiliazione: potremmo ricevere una commissione senza costi aggiuntivi per te. Il generatore resta gratuito e non dipende da questo.

Vedi il VPS di Contabo

Cosa fanno i file generati

Headscale è il sostituto open source del server di controllo di Tailscale: i tuoi dispositivi continuano a usare le app ufficiali di Tailscale, ma accedono al tuo server con --login-server. Servono tre cose: un indirizzo HTTPS pubblico sulla porta 443 uguale a server_url, un base_domain MagicDNS diverso da quell'indirizzo e un reverse proxy che lasci passare gli upgrade WebSocket se Headscale non gestisce da solo il TLS.

Il config.yaml è il file di esempio completo della versione 0.29.5 con i tuoi valori: tutte le chiavi sono presenti e nulla dipende da un valore predefinito non documentato. Con Docker il container ascolta su 0.0.0.0 nella propria rete e le porte sono pubblicate solo su 127.0.0.1, tranne 80 e 443 quando è Headscale a terminare il TLS. Dietro un reverse proxy sulla stessa macchina, trusted_proxies punta a localhost così gli IP reali dei client compaiono nei log.

Diversi comandi sono cambiati nelle ultime versioni, per questo molti tutorial falliscono: le chiavi preautenticate si creano ora con l'ID numerico dell'utente (lo mostra headscale users list), e un dispositivo che accede dal browser si approva con headscale auth register e il suo Auth ID. Il blocco dei primi passi usa la sintassi 0.29.

Caddy, nginx o TLS integrato?

Tre modi per servire Headscale in HTTPS, tutti documentati dal progetto. La scelta giusta dipende da cosa gira già sul server.

HTTPS gestito daCertificatoIdeale quandoAttenzione
Caddy (reverse proxy)Automatico, rinnovato da CaddyVuoi l'installazione più breve o altri siti sullo stesso VPSLe porte 80 e 443 devono arrivare a Caddy; il WebSocket funziona senza righe in più
nginx (reverse proxy)certbot, rinnovato dal suo timernginx serve già altri siti sulla macchinaLe intestazioni Upgrade e Connection sono obbligatorie, altrimenti i client non si collegano mai
Let's Encrypt integrato in HeadscaleAutomatico, rinnovato da HeadscaleSul VPS gira solo HeadscaleHeadscale occupa le porte 80 e 443; nessun altro servizio web su quell'IP

Domande frequenti

Qual è il config.yaml minimo per Headscale?
Headscale legge /etc/headscale/config.yaml. I valori da cambiare sono server_url (il tuo indirizzo HTTPS pubblico), listen_addr e dns.base_domain, che deve essere un dominio diverso da quello di server_url. La partenza più sicura è il file di esempio della tua versione esatta con quei valori modificati, che è ciò che produce questo generatore, perché alcune chiavi cambiano nome tra una versione e l'altra.
Perché tailscale up resta bloccato o fallisce con il mio server Headscale?
Nella maggior parte dei casi il reverse proxy non inoltra l'upgrade WebSocket (nginx senza le intestazioni Upgrade e Connection), server_url non corrisponde all'indirizzo usato dai client oppure il certificato non è attendibile. Prova curl https://tuo-dominio/health dall'esterno del server, poi leggi i log di Headscale. Una porta diversa da 443 è possibile, ma il client Tailscale presuppone 443 in alcuni casi.
Come creo una chiave preautenticata in Headscale 0.29?
Crea un utente con headscale users create <nome>, leggi il suo ID numerico con headscale users list, poi esegui headscale preauthkeys create --user <ID>. Per impostazione predefinita la chiave vale un'ora e si usa una sola volta. Sul dispositivo: tailscale up --login-server https://tuo-dominio --authkey <chiave>.
Mi serve il server DERP integrato?
No. Per impostazione predefinita Headscale fornisce ai client i relay DERP pubblici di Tailscale, usati solo quando una connessione diretta è impossibile. Attiva il DERP integrato se vuoi relay sotto il tuo controllo: serve aprire l'UDP 3478 e indicare l'IPv4 pubblico (e l'IPv6 se presente) del server.
Quanto deve essere grande il VPS per Headscale?
Molto poco: il server di controllo coordina solo chiavi e rotte, il traffico passa direttamente tra i dispositivi. I piani più piccoli bastano per una casa o un piccolo team. Conta avere un IPv4 pubblico, idealmente anche IPv6, e un provider che lasci aperte le porte 80, 443 e 3478. La stessa macchina può fare anche da exit node.