La mascotte orso polare di NordBastion in piedi in una scura sala di pietra nordica con una zampa su un obelisco runico scolpito a chiave di volta, un anello olografico ciano fluttuante di chiavi che si libra sopra di esso, e cinque glifi luminosi di dispositivi — laptop, telefono, tablet, torre server e globo — collegati direttamente tra loro in una mesh ciano brillante sospesa in alto mentre linee di chiavi punteggiate e tenui cadono dall'anello verso ciascun dispositivo, un rack server e una finestra ad arco illuminata dall'aurora boreale alle sue spalle
Guida pratica · Rete privata·19 min di lettura · 50 min operativi

Il proprio server di controllo.
La mappa è la cosa che vale la pena possedere.

Una VPN mesh ha bisogno di qualcuno che distribuisca le chiavi. Con Tailscale quel qualcuno è un'azienda; con WireGuard puro è lei, a mano, per sempre. Headscale è la terza risposta: lo stesso client open source, che dialoga con un server di coordinamento su un server che lei affitta in modo anonimo. Sei passaggi per un tailnet la cui mappa dei dispositivi, le regole di accesso e i relay di riserva sono tutti suoi — Headscale dietro Caddy, ACL messe per iscritto, MagicDNS puntato sul proprio resolver, un router di sottorete, un nodo di uscita e un DERP integrato. Il server costa $3.90 al mese. Testato su Debian 12.

I sei passaggi
  1. 01

    Scelta

    WireGuard, Tailscale e Headscale

  2. 02

    Provisioning

    Tre nomi fissati prima dell'avvio

  3. 03

    Distribuisci

    Headscale, Caddy e una sola configurazione

  4. 04

    Registrazione

    Utenti, chiavi di pre-autenticazione e client

  5. 05

    Routing

    Sottoreti, nodo di uscita e ACL

  6. 06

    Keep

    DERP, backup e aggiornamenti

Prima di iniziare · Cos'è un piano di controllo

Nessuno può leggere il traffico. Qualcuno però detiene ancora la mappa.

WireGuard è deliberatamente incompleto. È un tunnel piccolo, veloce e verificabile tra due chiavi pubbliche, e non ha alcuna opinione su come quelle chiavi si trovino a vicenda. Questa omissione è il motivo per cui il protocollo è così valido — ed è anche il motivo per cui una rete WireGuard di quindici dispositivi è un foglio di calcolo. Ogni peer ha bisogno della chiave pubblica e dell'indirizzo attuale di ogni altro peer, e ogni laptop che si sposta tra un ufficio, un treno e un hotel invalida parte di quel foglio di calcolo.

Una VPN mesh è la risposta a quel problema specifico, e vale la pena definirne con precisione la forma, perché è quella che decide di cosa ci si sta fidando. Il piano dati resta esattamente com'era: ogni dispositivo genera in locale la propria coppia di chiavi, ne conserva la metà privata e cifra direttamente verso i propri peer. Sopra di esso siede un piano di controllo — un piccolo servizio che raccoglie chiavi pubbliche ed endpoint, consegna a ogni dispositivo l'elenco dei peer con cui può parlare, e aiuta due dispositivi dietro router ostili a trovarsi. Quel servizio non detiene mai una chiave privata e non vede mai un byte in chiaro.

Ciò che detiene davvero è la mappa, e la mappa è più interessante di quanto la maggior parte delle persone immagini. Ogni nome di dispositivo e ogni nome utente. Ogni chiave pubblica. L'indirizzo pubblico da cui ogni dispositivo si sta collegando in questo momento, che è un registro in tempo reale di dove si trovano fisicamente il suo laptop e il suo telefono. Gli orari in cui ogni dispositivo si connette e si disconnette, che descrivono la sua giornata. E la policy che decide chi può raggiungere cosa, che descrive la sua organizzazione. Nulla di tutto ciò richiede malafede da parte di nessuno; è semplicemente a questo che serve un server di coordinamento.

C'è un'ulteriore proprietà che conta più dei metadati. Il piano di controllo è ciò che distribuisce le chiavi, quindi è anche ciò che potrebbe aggiungerne una. Un server di controllo compromesso, o costretto, può dire ai suoi dispositivi che una nuova macchina è un membro legittimo della rete — e i suoi dispositivi, facendo esattamente ciò per cui sono stati costruiti, cifreranno verso di essa. Tailscale prende la cosa abbastanza sul serio da aver costruito una funzione di firma proprio contro questo rischio. Il self-hosting risolve lo stesso problema dalla direzione opposta: la parte che potrebbe farlo è lei stesso. Quattro configurazioni, e cosa ciascuna rivela realmente:

Proprietà WireGuard manuale Tailscale, ospitato Headscale sul suo VPS Headscale + il proprio DERP
Chi può leggere il payloadNessuno tranne i peerNessuno tranne i peerNessuno tranne i peerNessuno tranne i peer
Chi detiene la mappa dei dispositiviLei, in un file di testoUn'azienda, nella propria giurisdizioneLei, sul suo VPSLei, sul suo VPS
Chi vede da dove si collegano i dispositiviSolo i peer stessiIl server di coordinamento, in modo continuoIl suo server, in modo continuoIl suo server, in modo continuo
Chi fa da relay quando un collegamento diretto fallisceNessuno — il collegamento semplicemente fallisceLa flotta di relay del providerAncora i relay del provider, di defaultIl suo relay, nel suo data center
Aggiungere il ventesimo dispositivoDiciannove modifiche di configurazioneUn comandoUn comandoUn comando
Lo scelga quandoPochi dispositivi, nessuno in roamingVuole zero operazioni e accetta la mappaVuole la mappa e può far girare un piccolo serverVuole la mappa e anche il percorso di riserva

La prima colonna non è un bersaglio di comodo. Per una manciata statica di server, WireGuard scritto a mano è davvero la risposta ingegneristicamente migliore, ed è un servizio in meno da aggiornare. Questa guida riguarda il punto in cui il foglio di calcolo smette di far ridere.

Passo 01 · Scelta

Le serve un piano di controllo? Conti i dispositivi che si spostano.

Ci sono tre risposte oneste a "voglio che le mie macchine si raggiungano privatamente", e solo una di esse è questa guida. WireGuard puro è la più piccola: un modulo del kernel, un file di configurazione per peer, nessun daemon oltre all'interfaccia, nulla da tenere aggiornato tranne il sistema operativo. Se i suoi dispositivi sono server con indirizzi fissi e può contarli su una mano, si fermi qui e legga invece la guida a WireGuard. Finirà con meno software e un elenco più corto di cose che possono rompersi.

Tailscale è la più grande delle tre: sotto il cofano lo stesso WireGuard, più un servizio di coordinamento, un NAT traversal che funziona da dietro quasi qualunque rete, una flotta di relay su più continenti, una console web, il single sign-on e un contratto di supporto. È software genuinamente eccellente e il piano gratuito copre comodamente una famiglia. Il prezzo non è in denaro: è che la mappa di ogni dispositivo che possiede, e il registro di dove ciascuno si collega, vivono nel database di un'azienda.

Headscale è la terza risposta, ed è più circoscritta di entrambe: una reimplementazione open source del server di coordinamento, gestita da lei, con cui dialoga lo stesso client ufficiale. Mantiene l'automazione e il NAT traversal; si assume un piccolo servizio da gestire, un set di funzionalità parziale e aggiornamenti che vanno letti con attenzione. Nessuno dovrebbe far finta che questo sia gratis. Compra esattamente una cosa, ed è quella a cui questo sito tiene davvero: nessun altro possiede la mappa.

La soglia dei cinque dispositivi

La configurazione manuale di WireGuard cresce con il quadrato della flotta: quattro peer sono sei collegamenti, dieci peer sono quarantacinque, venti peer sono centonovanta. Aggiunga un laptop in roaming, il cui endpoint cambia a ogni rete a cui si unisce, e la manutenzione smette di essere occasionale. In pratica il punto di svolta si colloca intorno a cinque dispositivi, oppure al primo dispositivo che si sposta ogni giorno, oppure alla prima regola di accesso che non riesce a esprimere come "tutti possono raggiungere tutto".

Un'altra cosa da decidere ora piuttosto che dopo, perché cambia cosa installa: se questa rete è solo per lei, o se altre persone vi si uniranno. Un tailnet per una sola persona può restare completamente aperto all'interno senza che accada nulla di male. Un tailnet con un collega, un collaboratore esterno o un familiare ha bisogno di regole di accesso scritte fin dalla prima settimana — passo 05 — e ha bisogno che gli utenti siano separati invece che tutti condividano lo stesso login. Deciderlo in anticipo costa un paragrafo; adattarlo in seguito costa un pomeriggio.

Passo 02 · Provisioning

Tre nomi, decisi prima del primo avvio. Tutti e tre sono difficili da cambiare.

Ordini prima il server. Nel pannello: Ordina → VPS → Sentinel, immagine Debian 12, nel bastione in cui vuole che la mappa risieda — Helsinki, Stoccolma, Oslo o Reykjavík. Non è richiesto alcun indirizzo email per aprire l'account e la fattura si salda in Monero, Bitcoin, Lightning o qualsiasi altro asset supportato. Scelga il bastione più vicino alla maggioranza dei suoi dispositivi se intende anche far girare il relay del passo 06; la latenza verso un relay è latenza su ogni connessione che trasporta.

Poi esegua la checklist di hardening della prima ora — SSH solo a chiave su una porta spostata, aggiornamenti automatici, un firewall a negazione predefinita. Tutto quanto segue presuppone un server che non sia già di qualcun altro, e questo vale più della maggior parte: è la macchina che decide quali chiavi sono fidate su ogni dispositivo che possiede.

Decida questi tre elementi prima che si registri qualcosa

Ogni dispositivo incorpora tutti e tre questi elementi nel proprio stato nel momento in cui si unisce, quindi cambiarne uno in seguito significa reiscrivere l'intera flotta a mano. Uno: l'URL del server di controllo — l'indirizzo HTTPS pubblico esatto che ogni client contatterà, schema e hostname inclusi. Due: il suffisso DNS del tailnet, il dominio per cui MagicDNS risponderà internamente; deve essere uno che lei controlla e non deve essere genitore o figlio dell'hostname del server di controllo, che è il singolo errore al primo avvio più comune in assoluto. Tre: gli intervalli di indirizzi che il tailnet distribuisce, convenzionalmente il blocco NAT carrier-grade 100.64.0.0/10 per IPv4 e un /48 unique-local per IPv6; lasci i valori predefiniti a meno che non collidano già con una rete che usa.

Un esempio pratico, e lo schema da copiare: il server di controllo risponde su vpn.example.com, il suffisso del tailnet è ts.example.com, e gli intervalli restano ai valori predefiniti. Noti che il suffisso è un fratello dell'hostname di controllo e non un suo genitore — vpn.example.com e ts.example.com condividono un dominio registrabile ma nessuno dei due contiene l'altro. Punti un record A — e un AAAA se vuole che sia raggiungibile via IPv6 — sul server, e lo lasci propagare prima di iniziare, perché il reverse proxy tenterà di ottenere un certificato per quel nome al primo avvio.

Poi scriva le regole del firewall mentre ancora nessuno è in ascolto. Il server di controllo è per necessità un endpoint HTTPS pubblico: ogni dispositivo, su ogni rete, deve poterlo raggiungere. La porta UDP serve solo se intende far girare un proprio relay al passo 06, ed è più facile aprirla ora che fare debug della sua assenza più avanti.

ufw default deny incoming
ufw allow 47222/tcp                  # administrative SSH, moved
ufw allow 80/tcp                     # ACME HTTP-01 challenge
ufw allow 443/tcp                    # the control server, and DERP over HTTPS
ufw allow 3478/udp                   # STUN, only if you run your own relay
ufw enable
ufw status numbered

Installi Docker dal repository ufficiale invece che dal pacchetto della distribuzione, in modo che Compose v2 sia presente e aggiornato. Poi crei le due directory che conterranno tutto ciò che vale la pena includere nel backup — una per la configurazione, una per lo stato — e resista alla tentazione di mettervi qualunque altra cosa.

curl -fsSL https://get.docker.com | sh
docker compose version

install -d -m 0750 /srv/headscale/config
install -d -m 0750 /srv/headscale/data
cd /srv/headscale
Passo 03 · Deploy

Due container e un file. Blocchi sempre la versione.

Headscale e Caddy, e nient'altro. Headscale ascolta in HTTP semplice all'interno della rete Docker; Caddy termina il TLS, ottiene il certificato al primo avvio e lo rinnova senza che gli venga chiesto. Il listener delle metriche resta su localhost, perché è una superficie di debug interna e non pubblica.

Una regola prima del file: blocchi l'immagine su una versione esatta. Headscale è software pre-1.0 che ha rinominato chiavi di configurazione e sottocomandi della CLI tra release minori più di una volta. Un tag mobile trasforma un normale riavvio del container in un'interruzione di un servizio il cui compito è farle raggiungere tutto il resto.

/srv/headscale/docker-compose.yml

services:
  headscale:
    image: docker.io/headscale/headscale:0.26            # pin it; never :latest
    container_name: headscale
    command: serve
    volumes:
      - ./config:/etc/headscale
      - ./data:/var/lib/headscale
    ports:
      - "3478:3478/udp"                                  # STUN, for your own DERP
    restart: unless-stopped

  caddy:
    image: caddy:2-alpine
    container_name: caddy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
    restart: unless-stopped

volumes:
  caddy_data:

/srv/headscale/Caddyfile

vpn.example.com {
    reverse_proxy headscale:8080
}

Questa è l'intera configurazione del proxy. Caddy parla HTTP/2 e fa l'upgrade delle connessioni di lunga durata senza che glielo si chieda, il che qui conta perché ogni client ne mantiene una aperta per ricevere gli aggiornamenti della mappa. Prenda il file di configurazione di esempio incluso nella versione che ha bloccato e lo modifichi invece di scriverne uno da zero — il file è lungo, la maggior parte sono valori predefiniti sensati, e le chiavi che contano sono queste:

/srv/headscale/config/config.yaml — the lines that matter

server_url: https://vpn.example.com          # exactly what clients will dial
listen_addr: 0.0.0.0:8080                    # inside the Docker network only
metrics_listen_addr: 127.0.0.1:9090          # debug surface, keep it local

prefixes:
  v4: 100.64.0.0/10
  v6: fd7a:115c:a1e0::/48

noise:
  private_key_path: /var/lib/headscale/noise_private.key

database:
  type: sqlite                               # postgres for a large fleet
  sqlite:
    path: /var/lib/headscale/db.sqlite

dns:
  magic_dns: true
  base_domain: ts.example.com                # NOT a parent or child of server_url
  nameservers:
    global:
      - 1.1.1.1                              # replaced by your own in step 05

Lo avvii, poi legga il log invece di dare per scontato. Un primo avvio che non riesce a ottenere un certificato, o che rifiuta il suffisso DNS perché si sovrappone all'hostname del server, lo dice chiaramente e poi si ferma.

docker compose up -d
docker compose logs -f headscale

# From your laptop — a control server that is up answers this:
curl -s https://vpn.example.com/health

Il primo avvio genera il materiale della chiave privata in /srv/headscale/data. Lo copi da qualche parte al sicuro subito, prima che si registri anche un solo dispositivo, e di nuovo dopo la prima registrazione: perdere quella chiave significa che ogni dispositivo rifiuta il server di cui si fidava, e l'unica riparazione è reiscriverli tutti a mano. Il passo 06 trasforma quella copia in un backup vero e proprio.

Passo 04 · Registrazione

Un utente, una chiave, un client. Poi verifichi se la connessione è andata direct.

Il comando headscale vive dentro il container, quindi ogni azione amministrativa è un docker exec. Crei prima un utente — un utente è un proprietario di dispositivi e l'unità a cui fanno riferimento le regole di accesso, quindi gli dia il nome di una persona o di un ruolo, non di una macchina.

hs() { docker exec -it headscale headscale "$@"; }

hs users create alice
hs users list                      # note the numeric id — newer releases want it

# A single-use key that expires in an hour is the right default.
hs preauthkeys create --user 1 --expiration 1h

Poi avvii il client ufficiale sul dispositivo, puntandolo sul proprio server invece di quello predefinito. Questo è un flag supportato, non un espediente — il client è open source e il server di login è un parametro.

# On the device (Debian/Ubuntu shown; every platform has an equivalent):
curl -fsSL https://tailscale.com/install.sh | sh

sudo tailscale up \
  --login-server https://vpn.example.com \
  --auth-key <the-key-you-just-created>

tailscale status
tailscale ip -4

Senza una chiave di pre-autenticazione il client stampa invece un URL; visitandolo compare un comando di registrazione da eseguire sul server, che è il percorso interattivo ed è comodo per un dispositivo che si ha davanti. In ogni caso, faccia il secondo dispositivo prima di festeggiare — una mesh di uno non dimostra nulla. Lo raggiunga con un ping tramite il suo indirizzo del tailnet, poi legga con attenzione l'output dello stato:

hs nodes list

# On a client, the word after the peer name is the one that matters:
tailscale status
#   100.64.0.2  laptop  alice  linux  active; direct 203.0.113.9:41641
#                                              ^^^^^^ direct, not relay

tailscale netcheck                 # why it chose what it chose

direct significa che i due dispositivi si sono trovati e il traffico è peer-to-peer. relay significa che passa attraverso un server DERP, il che funziona bene ma aggiunge latenza e mette una terza macchina sul percorso — e per default quella macchina non è sua. Il passo 06 serve proprio a decidere quale delle due sia.

Telefoni, tablet e la deviazione Apple

I desktop richiedono un flag da riga di comando. Android espone il server personalizzato nell'app, dietro il numero di versione nella schermata delle impostazioni. Le piattaforme Apple non hanno un campo nell'app: si installa un piccolo profilo di configurazione che imposta l'URL del server di controllo prima di accedere, operazione fastidiosa una volta sola ma permanente in seguito. Due accorgimenti fanno risparmiare tempo. Controlli la pagina per singolo client della documentazione di Headscale invece di procedere per tentativi, perché il flusso Apple è cambiato più di una volta. E disconnetta prima l'app dal servizio proprio di Tailscale — un'app che detiene già una sessione lì spesso rifiuterà un server diverso finché non è stata disconnessa, o reinstallata.

Due abitudini da adottare subito. Usi chiavi di pre-autenticazione monouso e di breve durata per le persone, e chiavi riutilizzabili o effimere solo per l'automazione che ne ha davvero bisogno — una chiave effimera registra un dispositivo che si rimuove da solo quando va offline, il che è esattamente giusto per un runner CI ed esattamente sbagliato per un laptop. E decida ora la sua posizione sulla scadenza delle chiavi: un dispositivo registrato porta una data di scadenza, e un dispositivo la cui chiave è scaduta smette di essere raggiungibile finché qualcuno non lo riautentica. Questa è una funzione di sicurezza su un laptop e un generatore di interruzioni su un server headless alle tre del mattino. Controlli come la sua versione gestisce la scadenza — i sottocomandi si sono spostati — e la imposti deliberatamente per ogni dispositivo invece di scoprire il valore predefinito nel modo peggiore.

Passo 05 · Routing

Annunciato non significa approvato. Due comandi, due macchine.

Un tailnet in cui ogni dispositivo raggiunge ogni altro dispositivo è già utile di per sé. Tre aggiunte lo trasformano in una rete vera e propria anziché in un insieme di tunnel, e tutte e tre condividono una caratteristica che trae in inganno molti: il client annuncia una capacità, e il server deve approvarla. Una rotta annunciata ma non approvata semplicemente non esiste, in silenzio, e il sintomo è che si riesce a fare il ping del router ma nulla dietro di esso risponde.

Un router di sottorete — porti un'intera LAN sul tailnet. Una macchina su una rete domestica o d'ufficio annuncia l'intervallo della rete; ogni altro dispositivo raggiunge quindi le stampanti, il NAS e le interfacce di gestione dietro di essa senza dover installare nient'altro lì. Attivi prima l'inoltro nel kernel, altrimenti i pacchetti si fermano al router senza alcun messaggio di errore.

# On the machine that sits inside the LAN:
echo 'net.ipv4.ip_forward = 1'          | sudo tee /etc/sysctl.d/99-ts.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-ts.conf
sudo sysctl -p /etc/sysctl.d/99-ts.conf

sudo tailscale up --login-server https://vpn.example.com \
  --advertise-routes=192.168.1.0/24 --accept-routes

# On the control server — approve it, or it does not exist.
# The subcommand moved between releases; check `hs nodes --help` first.
hs nodes list
hs nodes approve-routes --identifier 3 --routes 192.168.1.0/24

Un nodo di uscita — faccia uscire tutto attraverso il VPS. Lo stesso meccanismo con una rotta più ampia: un dispositivo che si annuncia come nodo di uscita offre di trasportare l'intera connessione internet di un altro dispositivo. Su una rete non fidata di un bar o di un hotel è esattamente ciò che serve, ed è la cosa più vicina a una VPN personale che questa guida offra.

# On the VPS that will do the exiting (forwarding must be on, as above):
sudo tailscale up --login-server https://vpn.example.com --advertise-exit-node

# Approve it on the control server, then on the laptop:
tailscale set --exit-node=100.64.0.1 --exit-node-allow-lan-access
tailscale set --exit-node=                    # turn it off again

Un nodo di uscita non è una VPN commerciale e non va venduto a se stessi come tale. Il suo indirizzo è solo suo ed è stabile, il che è eccellente contro il Wi-Fi del bar e inutile contro la correlazione a lungo termine tra siti diversi — il compromesso è spiegato nella guida pilastro. Noti anche che può far girare il nodo di uscita su un secondo VPS più economico e tenere il server di controllo completamente libero da traffico inoltrato.

Regole di accesso — le scriva prima che si unisca una seconda persona. La policy predefinita è consenti-tutto, il che è corretto per un tailnet di una sola persona e sbagliato nel momento in cui qualcun altro vi entra. La policy è un piccolo documento HuJSON: gruppi di utenti, tag per le macchine, e un elenco di regole che stabiliscono quali sorgenti possono raggiungere quali destinazioni su quali porte. Punti la configurazione al file, tenga il file sotto controllo di versione, e ricarichi dopo ogni modifica.

{
  "groups": {
    "group:admin":     ["alice"],
    "group:contractor":["bob"]
  },
  "tagOwners": {
    "tag:server": ["group:admin"],
    "tag:exit":   ["group:admin"]
  },
  "acls": [
    // Admins reach everything.
    { "action": "accept", "src": ["group:admin"], "dst": ["*:*"] },

    // The contractor reaches one machine, on two ports, and nothing else.
    { "action": "accept", "src": ["group:contractor"],
      "dst": ["tag:server:22,443"] }
  ],
  "autoApprovers": {
    "routes":   { "192.168.1.0/24": ["tag:server"] },
    "exitNode": ["tag:exit"]
  }
}

Due note su quel file. Il linguaggio della policy è quello di Tailscale, e Headscale ne implementa un sottoinsieme ampio e in crescita, non tutto — controlli la documentazione della sua versione prima di affidarsi a una regola esotica. E il punto in cui la policy risiede si è spostato: le release più vecchie indicavano un percorso nella configurazione di primo livello, quelle più nuove la raggruppano sotto una sezione policy con una modalità che può anche tenere le regole nel database. Entrambe sono documentate; quella che conta è quella che spedisce la sua versione bloccata.

MagicDNS — nomi brevi, e il proprio resolver ovunque. Con MagicDNS attivo, ogni dispositivo risponde a un nome breve all'interno del suffisso scelto al passo 02, quindi ssh nas funziona da qualunque luogo senza un file hosts. La seconda metà è quella interessante: il server di controllo invia anche un elenco di nameserver a ogni client, il che significa che il resolver costruito nella guida al resolver DNS privato può servire il suo telefono sui dati mobili — filtrando, mettendo in cache e senza registrare nulla — pur restando in ascolto su un indirizzo del tailnet che non è raggiungibile da internet in alcun modo.

dns:
  magic_dns: true
  base_domain: ts.example.com
  override_local_dns: true          # beat whatever DHCP handed the device
  nameservers:
    global:
      - 100.64.0.5                  # your resolver, on the tailnet
Passo 06 · Conservazione

Il proprio relay, il proprio backup. E aggiornamenti letti prima di essere applicati.

Il relay che ha dimenticato di stare usando. Quando due dispositivi non riescono ad aprire una connessione diretta — NAT simmetrico su entrambi i lati, un firewall che divora l'UDP, un operatore che fa qualcosa di creativo — il traffico ripiega su un relay DERP. Resta cifrato end-to-end, quindi il relay trasporta testo cifrato. Ciò che il relay vede è chi sta parlando con chi, quanto e quando. Di default, Headscale consegna ai suoi client la mappa di relay pubblica, e quei relay sono gestiti dall'azienda da cui si stava allontanando. Headscale include un relay integrato; attivarlo porta quel fallback nello stesso data center nordico di tutto il resto.

derp:
  server:
    enabled: true
    region_id: 999                  # custom regions live in the 900s
    region_code: "nb-hel"
    region_name: "Helsinki (self-hosted)"
    stun_listen_addr: "0.0.0.0:3478"
  urls:
    - https://controlplane.tailscale.com/derpmap/default   # remove for yours only
  auto_update_enabled: true
  update_frequency: 24h

Lasciare la mappa pubblica accanto alla propria regione è la scelta pragmatica di default: i client preferiscono il relay più vicino, quindi un dispositivo nello stesso emisfero ottiene il suo, e un dispositivo dall'altra parte del mondo non resta bloccato dietro un unico salto nordico. Rimuovere l'URL pubblico rende il tailnet strettamente autosufficiente, al prezzo di un fallback peggiore per i dispositivi lontani. Entrambe le scelte sono difendibili; scelga con consapevolezza, non per omissione.

Quattro file, fuori sede, cifrati. Il backup è abbastanza piccolo da risultare imbarazzante se manca: il database, il materiale della chiave privata, il file di configurazione e il file di policy. Insieme sono un errore di arrotondamento su qualunque bolletta di storage, e senza il materiale della chiave ogni dispositivo della rete rifiuta il server. Li invii da qualche parte che non sia questo server — idealmente una seconda giurisdizione, a cui serve la guida ai backup — e li ripristini una volta su un VPS usa e getta, deliberatamente, prima che ne abbia bisogno davvero.

# Stop briefly for a consistent SQLite copy, or use .backup on a live db.
docker compose stop headscale
tar czf /tmp/headscale-$(date +%F).tar.gz -C /srv/headscale config data
docker compose start headscale

restic -r sftp:backup@backup.example.com:/srv/restic backup \
       /tmp/headscale-$(date +%F).tar.gz

Gli aggiornamenti, che sono il vero rischio. Questo è software pre-1.0 e si comporta di conseguenza: le chiavi di configurazione sono state rinominate, i sottocomandi della CLI si sono spostati, e più di una release ha richiesto una migrazione documentata invece di un semplice riavvio. Nulla di tutto ciò è un motivo per evitarlo — è un motivo per avere una routine. Legga le note di rilascio prima di scaricare. Prenda prima l'archivio di cui sopra. Confronti il suo file di configurazione con l'esempio incluso nella nuova versione, perché è lì che le chiavi rinominate si fanno notare. Avanzi di una versione minore alla volta invece che di tre. E tenga annotato il vecchio tag dell'immagine, perché un rollback eseguibile in trenta secondi è ciò che rende l'intera operazione a basso rischio.

Poi imposti un promemoria mensile per controllare due cose: l'elenco dei dispositivi registrati, così le macchine dismesse sei mesi fa smettono di essere membri, e le date di scadenza, così nulla scompare silenziosamente in un brutto momento. Una VPN mesh è uno dei pochi servizi che fallisce in silenzio — tutto continua a funzionare finché non arriva la volta in cui le serve proprio il dispositivo la cui chiave era scaduta senza far rumore.

La parte onesta · Cosa non fa

Ha ripreso il controllo della mappa. Non è diventato invisibile.

Il self-hosting del piano di controllo è un miglioramento reale e specifico, e non è un gioco di prestigio. Cinque cose restano vere anche dopo aver fatto tutto quanto sopra, e conoscerle è la differenza tra una difesa vera e propria e una storia consolatoria.

Il server di controllo è un endpoint pubblico e nominato. Ogni dispositivo lo contatta, quindi ha un hostname, e quell'hostname viene pubblicato nei log di certificate transparency nel momento stesso in cui il certificato viene emesso. È individuabile anche se non ci si collega mai a esso, e il suo indirizzo è l'unica costante che tutti i suoi dispositivi hanno in comune. Usi un sottodominio di un nome che già pubblica, invece di uno che descrive cosa esso sia.

Headscale è una reimplementazione, e lo dichiara apertamente. Non è realizzato né supportato da Tailscale, la parità di funzionalità è parziale per costruzione, e parte di ciò che il prodotto ospitato vende — la console web, la flotta di relay pubblica, i percorsi di single sign-on rifiniti — o non esiste qui oppure è un progetto di terze parti che nessuno ha verificato. Legga la documentazione del progetto per sapere se una funzionalità esiste prima di costruirci un piano attorno, e tratti gli aggiornamenti come un compito, non come un processo in background.

I relay predefiniti restano comunque di qualcun altro. Finché non attiva il server DERP integrato, una connessione che non riesce ad andare direct ripiega sulla flotta di relay pubblica. Il payload resta comunque cifrato end-to-end e nessuno può leggerlo — ma il fatto che due dei suoi dispositivi stiano parlando, e quanto, transita su un'infrastruttura che non possiede. Questa è la parte della catena di fiducia che quasi tutti si perdono il primo pomeriggio.

Un nodo di uscita è un indirizzo stabile, non una folla. Instradare il suo traffico attraverso il proprio VPS sconfigge la rete del bar e il profilo dell'ISP. Non sconfigge la correlazione, perché quell'indirizzo appartiene solo a lei e non cambia. L'indirizzo condiviso di una VPN commerciale è peggiore sotto ogni aspetto tranne quello che conta per quella particolare minaccia.

La macchina è pur sempre dentro un edificio. Un server affittato gira su hardware in un data center con porte e personale. Ciò che cambia è che non esiste un indice a livello di prodotto dei suoi dispositivi, nessun database aziendale che registra da dove si collega ciascuno di essi, e nessuna informativa sulla privacy che possa essere modificata il prossimo trimestre. Ciò che non cambia è che il disco è fisico e non è a casa sua.

Ciò che ha effettivamente comprato, con precisione: l'elenco di ogni macchina che possiede, il registro di dove ciascuna si collega, e l'autorità di aggiungerne una nuova, sono tutti custoditi su un server che affitta senza un nome particolare. È un'affermazione circoscritta ed è reale. Vale ciò che costa solo se il passo 06 è stato completato — un piano di controllo self-hosted senza un ripristino testato non è un miglioramento della privacy, è un singolo punto di guasto con un branding migliore.

Dimensionamento · Cosa ordinare

Il piano di controllo è gratis. È il traffico che si paga.

Livello Mensile Risorse Cosa fa girare comodamente
Sentinel$3.902 vCPU · 4 GB · 120 GB · 1 GbpsIl server di controllo, un relay e un uso leggero come nodo di uscita. Il punto di partenza giusto.
Un secondo Sentinel$3.90Il nodo di uscita, su un server a parteTiene il traffico inoltrato lontano dal piano di controllo
Ravelin$16.908 vCPU · 16 GB · 480 GB · 2.5 GbpsUn nodo di uscita d'uso quotidiano per una famiglia, alla piena velocità di linea
Bulwark$32.9016 vCPU · 32 GB · 960 GB · 5 GbpsUn nodo di uscita aziendale e un relay affollato, insieme

Niente in questa tabella è dimensionato per il coordinamento. Il server di controllo mantiene una connessione inattiva per dispositivo e un database misurato in kilobyte; qualche centinaio di dispositivi non darà fastidio nemmeno al livello più piccolo. Ciò che consuma un server è il traffico inoltrato — connessioni in relay e, molto di più, un nodo di uscita che trasporta l'intera connessione internet di qualcuno. Dimensioni in base alla banda in uscita e al throughput di cifratura, e ricordi che la banda è illimitata su ogni livello, quindi l'unica domanda è quanto velocemente la vuole.

Note dal campo · Sei trappole

Sei modi in cui questo può andare storto. Due di essi sembrano problemi DNS.

Trappola 01 · Confusa

Il suffisso del tailnet si sovrappone all'hostname del server

Scegliere un suffisso MagicDNS che sia genitore o figlio dell'hostname del server di controllo rompe la risoluzione dei nomi in un modo che sembra un'interruzione DNS. Li mantenga fratelli: vpn.example.com per il server, ts.example.com per il tailnet.

Trappola 02 · Silenziosa

Una rotta annunciata e mai approvata

Il client segnala allegramente che sta annunciando 192.168.1.0/24 e nulla dietro il router risponde, perché il server non l'ha mai approvato. Non c'è alcun errore da nessuna parte. Approvi sul server, poi controlli l'elenco delle rotte invece del client.

Trappola 03 · Lenta

Tutto in relay, niente direct

Una rete che blocca l'UDP in uscita costringe ogni connessione a passare da un relay: funziona, è più lenta, e mette una terza macchina sul percorso. tailscale status restituisce relay invece di direct, e netcheck spiega il perché. Corregga il firewall oppure accetti consapevolmente il salto in più.

Trappola 04 · Esposta

La policy predefinita che consente tutto, con un ospite sul tailnet

Un tailnet appena creato lascia che ogni dispositivo raggiunga ogni altro dispositivo su qualsiasi porta. È corretto per una singola persona e sbagliato dal momento in cui si unisce il laptop di un collaboratore esterno — comprese le interfacce di gestione che non sapeva nemmeno esistessero. Scriva la policy prima dell'invito.

Trappola 05 · Fatale

La chiave privata di cui non è mai stato fatto il backup

Ricostruisca il server, ripristini il database, dimentichi il materiale delle chiavi — e ogni dispositivo rifiuterà il server di cui si fidava fino a ieri. Non esiste un recupero intelligente; c'è solo una giornata passata a reiscrivere i telefoni a mano. Copi la directory dei dati prima che si unisca il primo dispositivo.

Trappola 06 · Evitabile

Un tag di immagine mobile su un servizio pre-1.0

Le chiavi di configurazione e i sottocomandi della CLI sono stati rinominati tra una release minore e l'altra. Con :latest, un riavvio non correlato scarica una nuova versione e il piano di controllo dell'intera flotta si ferma. Blocchi il tag, legga le note di rilascio, aggiorni di proposito.

FAQ · VPN mesh self-hosted

Domande, con risposta.

Undici domande che emergono mentre si costruisce tutto questo — a partire dalle due che decidono se valga la pena costruirlo affatto.

Headscale è un prodotto ufficiale Tailscale?

No, e vale la pena essere precisi su cosa questo significhi. Headscale è una reimplementazione indipendente e open source del server di coordinamento — la parte di Tailscale che distribuisce chiavi pubbliche, endpoint e policy. Non è realizzato, venduto o supportato da Tailscale, non porta con sé alcun contratto di supporto commerciale, e se si rompe lei starà leggendo l'issue tracker invece di aprire un ticket. Ciò che fa davvero è parlare il protocollo che il client ufficiale e open source di Tailscale già parla, ed è per questo che il client funziona senza modifiche contro di esso. Ne conseguono due implicazioni pratiche. La parità di funzionalità è parziale e lo sarà sempre, perché il progetto insegue un bersaglio mobile mantenuto da un team molto più grande — controlli la documentazione del progetto per sapere se una funzionalità esiste prima di progettarci attorno. E gli aggiornamenti meritano più attenzione del solito salto di container: lo schema di configurazione e diversi sottocomandi della CLI sono stati rinominati tra una release minore e l'altra, il che è il modo più comune in assoluto in cui le persone rompono un'installazione funzionante.

Il server di coordinamento può leggere il mio traffico?

No — e questa è la parte dell'architettura che vale la pena capire invece di darla per fede. Ogni dispositivo genera in locale la propria coppia di chiavi WireGuard e la metà privata non lo lascia mai. Ciò che un dispositivo carica sul server di controllo è la sua chiave pubblica, i suoi endpoint attuali e alcuni metadati; ciò che scarica è lo stesso per ogni altro dispositivo che è autorizzato a raggiungere. I tunnel vengono poi negoziati direttamente tra i dispositivi, e la cifratura è normale WireGuard tra due chiavi che il server non ha mai posseduto. Quindi il server di controllo non può decifrare nulla, e questo vale anche per il server di Tailscale. Ciò che può fare è diverso e meno discusso: detiene la mappa. Nomi dei dispositivi, nomi degli utenti, chiavi pubbliche, l'IP pubblico da cui ogni dispositivo si sta collegando in questo momento, quale dispositivo si è svegliato alle tre del mattino, e la policy che stabilisce chi può raggiungere chi. È anche ciò che distribuisce le chiavi, quindi un server di controllo compromesso o costretto può aggiungere un dispositivo alla sua rete. Il self-hosting non risolve un problema matematico; ne sposta uno amministrativo su un server che possiede lei.

Cosa succede alla mia rete se il server di controllo va giù?

Molto meno di quanto ci si aspetti, il che è la parte rassicurante di questo disegno. I dispositivi mettono in cache l'ultima mappa di rete che hanno ricevuto, e i tunnel WireGuard esistenti sono peer-to-peer — non passano attraverso il server di controllo e non hanno bisogno di esso per continuare a funzionare. Un riavvio del VPS durante un normale giorno lavorativo è di solito invisibile. Ciò che si ferma è il cambiamento: nessun nuovo dispositivo può registrarsi, un dispositivo che si sposta su una nuova rete può impiegare più tempo a ritrovare i propri peer, le modifiche alla policy non si propagano, e qualunque nodo la cui chiave scade mentre il server è fermo non potrà rinnovarla. Quindi il modo corretto di pensare al server di controllo è come a un piano di controllo, non come a un percorso dati: un'interruzione è un fastidio, non una disconnessione. Detto questo, lo tratti come produzione. Lo metta in backup (passo 06), e se un intero reparto dipende dal tailnet, metta il server di controllo su un piccolo server tutto suo invece di condividerlo con qualcosa che viene riavviato spesso.

Headscale o WireGuard puro — quando vale davvero la pena di avere un piano di controllo?

Conti i suoi dispositivi e conti quanti di essi si spostano. WireGuard puro è una risposta eccellente per un insieme piccolo e statico: tre o quattro peer, endpoint fissi, un file di configurazione ciascuno, nulla da far girare a parte il modulo del kernel. È meno software, meno superficie d'attacco e meno manutenzione di qualunque cosa in questa guida, e la nostra guida a WireGuard lo copre da cima a fondo. Il costo è che WireGuard, deliberatamente, non ha distribuzione delle chiavi, quindi ogni nuovo dispositivo è una modifica su ogni altro dispositivo — un lavoro che cresce con il quadrato della flotta — e i client in roaming sul Wi-Fi dell'hotel e sui dati mobili hanno bisogno di qualcuno che continui a dire a tutti dove si sono spostati. Un piano di controllo è ciò che le compra questo. In pratica la soglia si colloca intorno ai cinque dispositivi, oppure al primo laptop che cambia rete ogni giorno, oppure alla prima volta che vuole una regola come "il laptop del collaboratore raggiunge il server di staging e nient'altro". Al di sotto di questa soglia, usi WireGuard e si goda la tranquillità.

L'app Tailscale sul mio telefono funziona con Headscale?

Sì — è lo stesso client ufficiale, e puntarlo su un server di controllo diverso è un'operazione supportata, non un espediente. La meccanica cambia a seconda della piattaforma, ed è lì che si perde una serata. Su Linux, macOS e Windows è un flag da riga di comando sul client (--login-server) o l'impostazione equivalente. Su Android l'opzione è esposta nell'app stessa, dietro il numero di versione nella schermata delle impostazioni. Su iOS, iPadOS e tvOS non c'è alcun campo nell'app: si installa un piccolo profilo di configurazione che imposta l'URL del server di controllo prima di accedere, operazione macchinosa la prima volta ma permanente in seguito. La documentazione di Headscale mantiene una pagina per ogni piattaforma proprio per questo, e vale la pena aprirla invece di procedere per tentativi, perché il flusso Apple in particolare è cambiato più di una volta. Un avvertimento che non è specifico di una piattaforma: un'app già connessa al servizio proprio di Tailscale di solito deve essere disconnessa — e a volte reinstallata — prima che accetti un server diverso.

Devo far girare un mio relay DERP?

Non per far funzionare la rete — ma è la differenza tra una privacy per lo più garantita e una privacy garantita in modo costante, quindi decida di proposito. I server DERP sono relay usati quando due dispositivi non riescono ad aprire una connessione diretta: NAT simmetrico su entrambi i lati, un firewall aziendale che divora l'UDP, un operatore mobile che fa qualcosa di creativo. Il traffico in relay resta comunque WireGuard cifrato end-to-end, quindi chi gestisce un relay vede testo cifrato, non contenuto. Ciò che vede sono metadati: quali due dispositivi stanno parlando, quanto e quando. Di default, Headscale consegna ai suoi dispositivi la mappa DERP pubblica di Tailscale, il che significa che quei relay sono di Tailscale — ha fatto il self-hosting del piano di controllo e ha lasciato il percorso dati di riserva all'azienda da cui si stava allontanando. Headscale include un server DERP integrato; attivarlo le dà un relay nello stesso data center nordico del server di controllo. Il compromesso onesto è la copertura: Tailscale fa girare relay su più continenti e lei ne fa girare uno solo, quindi un dispositivo dalla parte sbagliata del mondo è servito meglio dai loro. Farli girare entrambi, con il suo nella mappa, è una via di mezzo perfettamente ragionevole.

Posso far usare a tutto il tailnet il mio resolver DNS personale?

Sì, ed è una delle ragioni migliori per costruire tutto questo. Headscale può inviare una configurazione DNS a ogni dispositivo che si unisce, così il suo laptop sul Wi-Fi del bar e il suo telefono sui dati mobili risolvono entrambi attraverso un resolver che fa girare lei — con filtraggio, con una cache, e senza che la rete locale veda le query. Punti il nameserver globale del tailnet sull'IP del tailnet del server che fa girare il suo Unbound o AdGuard Home e imposti l'override in modo che vinca su qualunque cosa gli abbia assegnato il DHCP. Due cose da fare bene. Il resolver deve essere raggiungibile sul tailnet, non su internet pubblico — è proprio questo il punto, e significa anche che può finalmente chiudere la porta 53 al mondo. E MagicDNS, che dà a ogni dispositivo un nome breve all'interno di un suffisso scelto da lei, ha bisogno che quel suffisso sia uno che controlla e che non sia genitore o figlio dell'hostname del server di controllo; sbagliare questo è un guasto confuso che sembra un bug DNS ed è invece un bug di configurazione.

Quanto deve essere grande il VPS?

Per il solo piano di controllo: piccolo, e poi ancora più piccolo di così. Headscale è un singolo binario Go che contiene un piccolo database di dispositivi, chiavi e policy; il traffico di coordinamento è un rivolo di connessioni long-poll, una per dispositivo, che per la maggior parte del tempo non trasportano quasi nulla. Un Sentinel — 2 vCPU, 4 GB, 120 GB NVMe, $3.90 al mese — farà girare una famiglia, una piccola azienda, o qualche centinaio di dispositivi senza accorgersene. La questione del dimensionamento diventa interessante solo quando lo stesso server assume anche un secondo compito. Un relay DERP integrato inoltra traffico reale, quindi vuole banda in uscita più che core. Un nodo di uscita inoltra tutto il traffico di un dispositivo, quindi vuole banda in uscita, un tetto di banda generoso e una CPU capace di tenere il passo della cifratura alla velocità di linea. Se pianifica entrambi, dimensioni in base al traffico e tratti il server di controllo come l'errore di arrotondamento che è — o, meglio ancora, metta il nodo di uscita su un secondo server e mantenga il piano di controllo noioso.

Un nodo di uscita sul mio VPS personale è la stessa cosa che usare una VPN commerciale?

Tecnicamente simile, e in termini di privacy quasi l'opposto, quindi vale la pena avere le idee chiare. Un nodo di uscita instrada l'intera connessione internet di un dispositivo attraverso il suo VPS, così i siti web vedono l'indirizzo del VPS invece del suo indirizzo di casa o dell'hotel, e la rete locale vede un unico tunnel cifrato invece della sua navigazione. Fin qui corrisponde a una VPN commerciale. La differenza è la folla. L'indirizzo di una VPN commerciale è condiviso da migliaia di clienti tra loro estranei, il che è precisamente ciò che rende difficile attribuirle il traffico; l'indirizzo del suo nodo di uscita è usato da lei, stabilmente, per sempre. Contro una rete di un bar che spia o un ISP che costruisce un profilo, il nodo di uscita è eccellente. Contro un osservatore che correla l'attività tra più siti nell'arco di mesi, un indirizzo dedicato è un identificatore duraturo, uno condiviso non lo è. Usi il nodo di uscita per ciò in cui eccelle — reti locali non fidate, raggiungere i propri servizi, un indirizzo stabile per cose che se lo aspettano — e legga la guida pilastro per la parte del modello di minaccia che non copre.

Di cosa devo esattamente fare il backup?

Quattro cose, e solo una di esse è ovvia. Il database — SQLite di default, PostgreSQL se lo ha spostato — contiene utenti, dispositivi, chiavi pubbliche, rotte e chiavi di pre-autenticazione. Il materiale della chiave privata generato al primo avvio è la parte che si dimentica: lo perda e ogni dispositivo rifiuterà il server con cui parlava da un anno, il che significa reiscrivere l'intera flotta a mano. Il file di configurazione conta perché codifica i tre nomi del passo 02, e ricostruirli a memoria è il modo in cui capita di cambiarne uno per sbaglio. E il file di policy, se tiene le regole di accesso su disco, è la cosa che meno vorrebbe dover riscrivere. Tutti e quattro vivono in due directory e insieme pesano meno di una fotografia. Li cifri, li invii a una macchina che non è questa — idealmente in un'altra giurisdizione, a cui serve la guida ai backup — e li ripristini una volta su un VPS usa e getta, di proposito, così sa che il file che ha è il file di cui ha bisogno.

A NordBastion importa se faccio girare un server di controllo e un nodo di uscita sullo stesso VPS?

Un server di controllo è un carico di lavoro ordinario e ben educato — un po' di HTTPS, un po' di UDP, praticamente nessun traffico — e non c'è nulla nella politica di utilizzo accettabile che lo riguardi. Un nodo di uscita merita una riflessione in una frase, non una lezione sulle policy: tutto ciò che un dispositivo invia attraverso di esso esce da internet dall'indirizzo del suo VPS, sotto il suo account, quindi qualunque cosa facciano i suoi dispositivi è ciò per cui quell'indirizzo sarà conosciuto. Va benissimo così, ed è esattamente a questo che serve la funzione; è anche il motivo per cui condividere un nodo di uscita con persone che non conosce è una cattiva idea, allo stesso modo di un relay aperto a chiunque. La banda è illimitata su ogni livello e il traffico in relay è traffico normale, quindi un server DERP e un nodo di uscita sono entrambi inclusi anziché misurati a consumo. Al di là di questo: l'account non richiede il suo nome, la fattura si salda in Monero o Bitcoin, e la macchina che custodisce la mappa di ogni dispositivo che possiede non è indicizzata da nessuno.

Ottenere il server

Un piano di controllo tutto suo, su un account che non porta il suo nome. Senza KYC, pagabile in cripto.

Sentinel — 2 vCPU e 4 GB per $3.90 al mese, a Helsinki, Stoccolma, Oslo o Reykjavík. Sufficiente per Headscale, Caddy e un proprio relay DERP, con margine per il nodo di uscita se lo vuole sullo stesso server. Nessuna email alla registrazione, nessun documento d'identità, e nessun database aziendale che tenga l'elenco di ogni dispositivo che possiede.

Ultima revisione · 2026-10-12 · Fonti · Documentazione di Headscale (riferimento alla configurazione, setup client, ACL, DERP, CLI remota), documentazione del client Tailscale e del nodo di uscita, paper del protocollo WireGuard, documentazione di Caddy · Cadenza · annuale

Hosting privato, costruito nel Nord.