1255 parole
6 minuti
Headscale: La Tua VPN Self-Hosted con la Potenza di Tailscale

Cos’è una VPN#

La tecnologia VPN negli ultimi anni sta diventando sempre più pervasiva e sebbene a volte venga spacciata come la soluzione a tutti i problemi, essa presenta delle caratteristiche che possono fare gola a molte persone.

L’utente novizio potrebbe sfruttare una rete VPN con server in un altro paese per collegarsi al proprio servizio di streaming preferito e accedere a contenuti bloccati o non disponibili.
L’utente esperto sfrutterebbe la VPN nella sua vera natura di Virtual Private Network al fine di avere un accesso autenticato e confidenziale alla propria rete aziendale o casalinga.

Dato che in questo blog (nonchè articolo per il buon Morro) siamo generalmente degli smanettoni abbastanza esperti, quello che vogliamo fare oggi è setuppare una VPN nel modo più semplice possibile riuscendo magari ad ottenere qualche funzionalità extra.

Wireguard#

Quando si approccia a setuppare una rete VPN generalmente si predilige un protocollo tra: OpenVPN, Wireguard e Ipsec. La differenza fra questi sta nelle funzioni avanzate fornite all’utente. OpenVPN per esempio supporta ACL avanzate, autenticazione multi-fattore ma risulta allo stesso tempo più lenta e pesante di Wireguard che è nata con lo scopo di essere veloce ed efficente.
Wireguard è inoltre una soluzione molto più moderna e leggera e viene spesso utilizzata come backbone in altre soluzioni come Tailscale.

Arhitettura Hub and Spoke con Wireguard#

Wireguard crea dei tunnel encriptati leggerissimi ma la maggior parte delle volte questi tunnel sono strutturati secondo una architettura Hub and Spoke dove ogni client si connette a un “coordinatore” centrale 1. Questa architettura è generalmente preferita perché richiede la configurazione e l’esposizione di un solo hub. Come vediamo nell’immagine, in una rete con 10 nodi vengono generati al massimo 10 tunnel.

hub

Problematiche#

Hub and Spoke funziona bene ma ha i suoi svantaggi:

  • le grosse company non hanno solitamente un singolo punto da designare come VPN hub
  • aziende multinazionali o dislocate in varie regioni di solito hanno un singolo accentratore VPN e poi impostano vari tunnel IPsec verso le varie sedi
IMPORTANT

Questo porta a svantaggi in termini di latenza e affidabilità dato che gli utenti remoti che vogliono collegarsi a un datacenter possono trovarsi lontano dall’accentratore VPN e lo stesso datacenter finale potrebbe trovarsi a sua volta molto lontano da quest’ultimo.

hub

Mesh Network#

Come abbiamo detto, Wiregaurd crea tunnel crittografati estremamente leggeri; non sarebbe bello se fosse possibile collegare i singoli nodi in modo diretto uno all’altro creando una mesh network?!
Con Wireguard è possibile ma potrebbe essere complesso:

  • Una rete con 10 nodi richiede 90 configurazioni di tunnel WireGuard.
  • Ogni nodo deve conoscere la propria chiave + 9 altre, aggiornandole ad ogni cambio.
  • I nodi devono trovarsi e riconnettersi, ma gli IP sono spesso dinamici.
  • Firewall e NAT complicano le connessioni in luoghi pubblici (caffè, hotel, aeroporti).
  • Senza un hub centrale, audit e blocco del traffico tra nodi diventano complessi.

mesh

Tailscale#

Tailscale risolve tutti questi problemi e lo fa in modo automatico!

Esso é di fatto un coordinatore leggero che si interpone fra i vari nodi e che si occupa di fare tutto il lavoro sporco al fine di configurare correttamente tutti i tunnel VPN.
Tailscale è molto più avanzato di così: include infatti varie strategie avanzate di Net Traversal 2 che permettono ai singoli dispositivi di superare firewall e creare connessioni.

WARNING

Come evidenziato in questo post su Reddit 3 se usi Tailscale, stai esternalizzando una parte della tua rete a un’azienda finanziata da venture capital e sarai dipendente da eventuali modifiche ai loro Termini di Servizio.

Esiste una versione di Tailscale completamente open e self hostable chiamata Headscale 4.

Headscale#

Headscale mira a implementare un’alternativa self-hosted e open-source al server di controllo di Tailscale. Sul sito ufficiale di Headscale viene mostrato passo passo come installare l’intero sistema.

Prerequisiti#

  • server con IPv4 pubblico
  • Dominio con certificato https
  • utente dedicato headscale
  • Headscale è disponibile via HTTPS su porta 443 di default

Setup dominio con certificato#

Per semplicità usiamo duckdns.

  1. Login e ci annotiamo il token e la mail
  2. Creiamo un mapping hs-devstone all’ip privato della macchina su cui hostiamo Headscale
  3. Nel prossimo punto configureremo un reverse proxy Caddy che richiederà ogni volta un certificato aggiornato per il dominio hs-devstone

Duckdns

Setup reverse proxy Caddy#

Usiamo Caddy come reverse proxy dato che è in grado di rinnovare certificati autonomamente utilizzando DNS challenge e inoltre è di facile configuraizione.

NOTE

Caddy non supporta nativamente duckdns quindi dobbiamo buildare un’immagine Caddy al volo.

  1. Creiamo una cartella dockerfile-caddy che contiene il Dockerfile per la creazione dell’immagine di Caddy
FROM caddy:builder AS builder  
RUN xcaddy build --with github.com/caddy-dns/duckdns 
FROM caddy:2 
COPY --from=builder /usr/bin/caddy /usr/bin/caddy  
  1. Creiamo un Caddyfile per impostare le regole di reverse proxy.
{$DOMAIN}:443 {
  log {
    level INFO
    output file {$LOG_FILE} {
      roll_size 10MB
      roll_keep 10
    }
  }

  # Use the ACME DNS-01 challenge to get a cert for the configured domain.
  tls {
    dns duckdns {$DUCKDNS_TOKEN}
  }

  # This setting may have compatibility issues with some browsers
  # (e.g., attachment downloading on Firefox). Try disabling this
  # if you encounter issues.
  encode gzip

  # Proxy everything else to Headscale
  reverse_proxy http:/headscale:8080
}
  • $DOMAIN: è il dominio che abbiamo in duckdns e che imposteremo nel docker compose
  • $LOG_FILE: sarà il nome del file di log
  • $DUCKDNS_TOKEN: sarà il token Duckdns

Creazione container Docker#

  1. Creiamo la cartella che conterrà la configurazione Headscale
mkdir -p ./headscale/config
cd ./headscale/config
  1. Scarichiamo il template di configurazione da qui e lo salviamo in ./headscale/config/config.yaml. Cambiamo i valori come segue:
server_url: https://hs-devstone.duckdns.org

# Address to listen to / bind to on the server
#
# For production:
# listen_addr: 0.0.0.0:8080
listen_addr: 0.0.0.0:8080

# Address to listen to /metrics, you may want
# to keep this endpoint private to your internal
# network
#
metrics_listen_addr: 0.0.0.0:9090

# Address to listen for gRPC.
# gRPC is used for controlling a headscale server
# remotely with the CLI
# Note: Remote access _only_ works if you have
  1. Creiamo un docker-compose.yaml in ./headscale. Servizi:
  • headscale: esposto su porta 8080 e 8090 su container headscale
services:
  headscale:
    image: headscale/headscale
    restart: unless-stopped
    container_name: headscale
    volumes:
      # Please change <CONFIG_PATH> to the fullpath of the config folder just created
      - ./config:/etc/headscale
    command: serve
  caddy:
    build: ./dockerfile-caddy
    container_name: caddy
    pull_policy: build
    restart: always
    ports:
      - 443:443
    volumes:
      # - ./caddy:/usr/bin/caddy  # Your custom build of Caddy.
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./caddy-config:/config
      - ./caddy-data:/data
    environment:
      - DOMAIN=https://hs-devstone.duckdns.org                # Your domain.
      - EMAIL=luca201194@gmail.com                            # The email address to use for ACME registration.
      - DUCKDNS_TOKEN=aaa33e43-1333-4e92-93ad-994737b01dee    # Your Duck DNS token.
      - LOG_FILE=/data/access.log
  1. Creazione e run del container
docker compose up -d --build # crea container e run in background
docker logs --follow headscale # seguiamo i log
docker compose ps # vediamo se è partito

Esempio di log

 docker logs --follow headscale
headscale  | 2025-03-07T13:55:13Z INF No private key file at path, creating... path=/var/lib/headscale/noise_private.key
headscale  | 2025-03-07T13:55:13Z INF Opening database database=sqlite3 path=/var/lib/headscale/db.sqlite
headscale  | 2025-03-07T13:55:13Z INF home/runner/work/headscale/headscale/hscontrol/app.go:570 > Clients with a lower minimum version will be rejected minimum_version=v1.62.0
headscale  | 2025-03-07T13:55:13Z WRN Listening without TLS but ServerURL does not start with http://
headscale  | 2025-03-07T13:55:13Z INF listening and serving HTTP on: 0.0.0.0:8080
headscale  | 2025-03-07T13:55:13Z INF listening and serving debug and metrics on: 0.0.0.0:9090

Verifica che tutto funzioni andando su https://hs-devstone.duckdns.org/windows e vediamo se il certificato è autentico certificate 5. Creazione utente

docker exec -it headscale headscale users create myfirstuser

Registrazione clients#

Android#

Per aggiungere un server esterno basta andare in settings/Accounts/ e cliccare sui 3 puntini Registrazione server Login

Aggiungiamo uno o più nodi a headscale:

docker exec -it headscale headscale nodes register --user myfirstuser --key TNXkxpAYUeDHunCIz7aigkDh
> Node localhost registered

Mac Os#

Funziona allo stesso modo di Android, viene generato un link di associazione

Test finale#

Headscale in combinazione con i client Tailscale permette di creare una Rete VPN Mesh e lo fa in modo estremamente semplice.
Questo ha effetti positivi nelle performance dato che possiamo instaurare connessioni punto-punto senza dover passare per un accentratore. Statistiche

Come vediamo in Local Send abbiamo 2 reti a cui è connesso il dispositivo. Local Send

Footnotes#

  1. Come funziona Tailscale

  2. Net Traversal video

  3. A word of caution about Tailscale

  4. Headscale

Headscale: La Tua VPN Self-Hosted con la Potenza di Tailscale
https://thedevstone.com/posts/headscale-tailscale-selfhosted/
Autore
The Devstone
Pubblicato il
2025-03-08