- 1. Headscale on‑prem con VPS, Cloudflare e Reverse SSH Tunnel
- 1.1. VPS Esterno
- 1.2. Scopo del documento
- 1.3. Obiettivo architetturale
- 1.4. Schema logico
- 1.5. Componenti
- 1.6. Reverse SSH Tunnel (cuore dell’architettura)
- 1.7. NGINX (VPS)
- 1.8. Verifiche di funzionamento
- 1.9. Headscale – gestione
- 1.10. Client Tailscale
- 1.11. Considerazioni di sicurezza
- 1.12. Punto chiave da ricordare
- 1.13. Stato finale
- 1.14. Operazioni Headscale
1. Headscale on‑prem con VPS, Cloudflare e Reverse SSH Tunnel
1.1. VPS Esterno
https://cloudserver.net/billing/index.php?rp=/login
1.2. Scopo del documento
Questo README serve come memoria tecnica permanente dell’architettura Headscale adottata. Va usato come riferimento in caso di:
- problemi di connettività
- migrazioni
- ripristino dopo downtime
- troubleshooting (Tunnel / TLS / DNS / Tailscale)
1.3. Obiettivo architetturale
- Headscale self‑hosted on‑prem (VM Proxmox, IP dinamico)
- Nessuna porta esposta verso Internet dalla rete domestica
- Endpoint pubblico stabile e TLS valido
- Compatibile con client Tailscale ufficiali (macOS, Android, Linux)
1.4. Schema logico
[Tailscale Client]
|
| HTTPS (443)
v
[Cloudflare Proxy]
|
| HTTPS (443) – Origin Cert
v
[VPS pubblico]
NGINX (443/80)
|
| proxy_pass → 127.0.0.1:8080
v
[Reverse SSH Tunnel]
|
| SSH outbound only
v
[VM Headscale on‑prem]
headscale :8080
1.5. Componenti
1.5.1. VM on‑prem (Headscale)
- Hypervisor: Proxmox
- Rete: LAN domestica (IP dinamico)
-
Servizio:
-
headscale - Porta locale:
127.0.0.1:8080
Percorsi importanti:
1.5.2. VPS pubblico
- IP pubblico statico
- DNS:
headscale.enricomarogna.com -
Servizi:
-
nginx sshd
Porte aperte:
- 80 (HTTP → redirect)
- 443 (HTTPS)
- 22 (SSH, solo key)
1.5.3. Cloudflare
- DNS proxied (orange cloud)
- Modalità SSL: Full (strict)
-
Certificati:
-
Origin Certificate Cloudflare installato su VPS
1.6. Reverse SSH Tunnel (cuore dell’architettura)
Il VPS non connette verso casa. È la VM Headscale che apre una connessione SSH outbound persistente verso il VPS.
1.6.1. Chiave SSH
Generata sulla VM Headscale:
Installata su VPS:
1.6.2. Systemd service (VM Headscale)
File:
Contenuto:
[Unit]
Description=Reverse SSH tunnel for Headscale
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/lib/autossh/autossh -M 0 -N \
-i /root/.ssh/hs_tunnel \
-o BatchMode=yes \
-o IdentitiesOnly=yes \
-o StrictHostKeyChecking=yes \
-o UserKnownHostsFile=/root/.ssh/known_hosts \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-o ExitOnForwardFailure=yes \
-R 127.0.0.1:8080:127.0.0.1:8080 root@<IP_VPS>
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Comandi utili:
systemctl daemon-reload
systemctl enable --now headscale-tunnel
systemctl status headscale-tunnel
journalctl -u headscale-tunnel
1.7. NGINX (VPS)
1.7.1. VirtualHost HTTPS
Path tipico:
Config:
server {
listen 443 ssl;
server_name headscale.enricomarogna.com;
ssl_certificate /etc/ssl/cloudflare/headscale.crt;
ssl_certificate_key /etc/ssl/cloudflare/headscale.key;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
Test:
1.8. Verifiche di funzionamento
1.8.1. Sul VPS
1.8.2. Da Internet
Risposta attesa:
1.9. Headscale – gestione
1.9.1. Creazione Preauth Key
1.9.2. Lista nodi
1.10. Client Tailscale
1.10.1. Login macOS (CLI)
tailscale up \
--reset \
--login-server=https://headscale.enricomarogna.com \
--auth-key=<KEY> \
--accept-routes
1.10.2. Stato
1.11. Considerazioni di sicurezza
- Nessuna porta aperta verso la LAN domestica
- Solo traffico outbound dalla VM on‑prem
-
Cloudflare protegge da:
-
scansioni
- DDoS
- esposizione diretta IP VPS
- SSH solo con chiave
1.12. Punto chiave da ricordare
👉 Se qualcosa non funziona:
- verificare tunnel SSH
- verificare nginx sul VPS
- verificare Cloudflare (proxy ON)
- solo dopo guardare Headscale
1.13. Stato finale
✔ Headscale on‑prem ✔ Tunnel persistente ✔ TLS valido ✔ Client Tailscale ufficiali compatibili ✔ Nessuna dipendenza SaaS
Documento creato come single source of truth.
1.14. Operazioni Headscale
Questa sezione raccoglie tutti i comandi operativi di Headscale usati e da usare in futuro per la gestione quotidiana (utenti, nodi, chiavi, debug).
1.14.1. Percorsi e servizio
# binario
/usr/bin/headscale
# configurazione
/etc/headscale/config.yaml
# database (default sqlite)
/var/lib/headscale/db.sqlite
# servizio systemd
systemctl status headscale
1.14.2. Gestione utenti
# lista utenti
headscale users list
# crea nuovo utente
headscale users create NOMEUTENTE
# elimina utente
headscale users destroy NOMEUTENTE
Nota: l'utente NON è una mail reale. È solo un namespace logico (es: macosm2, laptop, server, ecc.).
1.14.3. Gestione preauth keys
# lista chiavi di un utente
headscale preauthkeys list --user NOMEUTENTE
# crea chiave riutilizzabile (90 giorni)
headscale preauthkeys create \
--user NOMEUTENTE \
--reusable \
--expiration 90d
# crea chiave one-shot
headscale preauthkeys create \
--user NOMEUTENTE \
--expiration 24h
Output esempio:
Sul client:
sudo tailscale up \
--login-server=https://headscale.enricomarogna.com \
--auth-key=CHIAVE \
--accept-routes
1.14.4. Gestione nodi
# lista nodi
headscale nodes list
# rinomina nodo
headscale nodes rename ID_NODO nuovo-nome
# elimina nodo
headscale nodes delete ID_NODO
Campi importanti da controllare:
IP addresses(es: 100.64.0.x)Connected(online/offline)Expired
1.14.5. Debug e troubleshooting Headscale
# log runtime
journalctl -u headscale -f
# test endpoint salute
curl http://127.0.0.1:8080/health
# verifica porta locale
ss -ltnp | grep 8080
Se /health risponde {"status":"pass"} → Headscale OK.
1.14.6. Reset completo client (macOS / Linux)
sudo tailscale logout
sudo tailscale up --reset \
--login-server=https://headscale.enricomarogna.com
1.14.7. Versioni client/server
⚠️ Warning frequente ma non bloccante:
Headscale non richiede versioni identiche, purché compatibili.