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.
Caddy è la via più breve. Scegli nginx se gira già sul server, il TLS integrato se sul VPS gira solo Headscale.
- 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
---
# 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
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:
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}
}
}
{
"tagOwners": {
"tag:exit": [
"admin@"
]
},
"autoApprovers": {
"exitNode": [
"tag:exit"
]
}
}
#!/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
# 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.
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 da | Certificato | Ideale quando | Attenzione |
|---|---|---|---|
| Caddy (reverse proxy) | Automatico, rinnovato da Caddy | Vuoi l'installazione più breve o altri siti sullo stesso VPS | Le porte 80 e 443 devono arrivare a Caddy; il WebSocket funziona senza righe in più |
| nginx (reverse proxy) | certbot, rinnovato dal suo timer | nginx serve già altri siti sulla macchina | Le intestazioni Upgrade e Connection sono obbligatorie, altrimenti i client non si collegano mai |
| Let's Encrypt integrato in Headscale | Automatico, rinnovato da Headscale | Sul VPS gira solo Headscale | Headscale occupa le porte 80 e 443; nessun altro servizio web su quell'IP |