Lockdown con Tailscale e Firewall
Prima cosa su una nuova VPS: installa Tailscale, connettiti via Tailscale, poi blocca il firewall in modo che solo tu (via Tailscale) e Cloudflare (per il traffico web) possiate raggiungere il server. Nessun altro.
Una VPS è come il tuo laptop, ma collegata a tutta internet. Miliardi di persone possono sondarla, provare a bucarla e sfruttarla. Tu la vuoi accessibile solo a te. E se ci ospiti un sito, vuoi che solo Cloudflare arrivi all'origin, così sta davanti e blocca gli attacchi. Non esporre mai una VPS direttamente al world wide web. In pratica, parliamo del world wild web.
Questa dovrebbe essere una cosa banale per qualsiasi VPS. In un mondo ideale, ogni provider di VPS userebbe Tailscale (o simile) di default e lo renderebbe l'unica via d'accesso. Finché non succede, fallo a mano.
Il workflow
- Crea il server Hetzner (o qualsiasi VPS).
- Connettiti via SSH una volta usando l'IP pubblico (serve un accesso iniziale).
- Installa Tailscale e collegati.
- Apri una nuova sessione SSH via il tuo IP Tailscale e verifica che funzioni.
- Blocca il firewall: SSH solo da Tailscale, HTTPS solo da Cloudflare.
- Chiudi la sessione SSH pubblica. Da ora in poi ti colleghi solo via Tailscale.
Installa Tailscale
Connettiti via SSH al server come root (o con sudo):
ssh root@YOUR_SERVER_IP
Installa Tailscale:
curl -fsSL https://tailscale.com/install.sh | sh
Collegati alla tua rete Tailscale. Per server headless usa una auth key (la generi su Tailscale Admin Console):
tailscale up --auth-key=tskey-auth-xxxxxxxxxxxx
Oppure, se hai display e browser:
tailscale up
Recupera il tuo IP Tailscale:
tailscale ip -4
Output di esempio: 100.x.x.x. Quello è il tuo indirizzo privato Tailscale.
Verifica l'accesso Tailscale
Dalla tua macchina locale (con Tailscale installato), apri un nuovo terminale:
ssh [email protected]
Sostituisci 100.x.x.x con l'IP da tailscale ip -4. Se ti colleghi, Tailscale funziona. Tieni aperta questa sessione. Non chiudere ancora la sessione su IP pubblico.
Blocca il firewall
Restringerai:
- SSH (porta 22 o 2222): solo da IP Tailscale (
100.64.0.0/10) - HTTPS (porta 443): solo dai range IP di Cloudflare
- HTTP (porta 80): solo da Cloudflare (per i redirect verso HTTPS)
Tutto il resto è negato.
UFW sul server
Docker bypassa UFW per le porte pubblicate. Per SSH e 80/443 sull'host, UFW funziona. Se usi Coolify, le sue porte (8000, 6001, 6002) vanno restritte tramite il Cloud Firewall di Hetzner.
Resetta UFW e aggiungi le regole:
ufw default deny incoming
ufw default allow outgoing
# SSH solo da Tailscale (100.64.0.0/10 è il range CGNAT che Tailscale usa)
ufw allow from 100.64.0.0/10 to any port 22 proto tcp
# Oppure se usi la porta 2222 per SSH:
# ufw allow from 100.64.0.0/10 to any port 2222 proto tcp
#
# Se Coolify gira sullo stesso host, devi anche permettere alle reti Docker di raggiungere SSH
# (vedi sezione "Coolify sullo stesso server" più sotto).
# HTTP/HTTPS solo da Cloudflare
# Recupera gli IPv4 e IPv6 di Cloudflare e poi aggiungi le regole (vedi sotto)
ufw --force enable
Range IP di Cloudflare
Cloudflare pubblica i range IPv4 e IPv6. Recuperali e permettili:
# IPv4
for ip in $(curl -s https://www.cloudflare.com/ips-v4); do
ufw allow from $ip to any port 80 proto tcp
ufw allow from $ip to any port 443 proto tcp
done
# IPv6
for ip in $(curl -s https://www.cloudflare.com/ips-v6); do
ufw allow from $ip to any port 80 proto tcp
ufw allow from $ip to any port 443 proto tcp
done
Esegui questo prima di ufw enable se stai costruendo le regole da zero. Oppure eseguilo e poi fai ufw reload.
Hetzner Cloud Firewall
Se usi Hetzner Cloud, puoi anche (o invece) usare il Cloud Firewall di Hetzner. Si applica a livello di rete prima che il traffico raggiunga il server. Crea un firewall con:
| Porta | Protocollo | Sorgente | Scopo |
|---|---|---|---|
| 22 (o 2222) | TCP | 100.64.0.0/10 | SSH (solo Tailscale) |
| 80 | TCP | Cloudflare IPv4 + IPv6 | HTTP |
| 443 | TCP | Cloudflare IPv4 + IPv6 | HTTPS |
Per Coolify (8000, 6001, 6002), aggiungi regole che permettano solo il tuo range Tailscale o il tuo IP. Vedi Server Setup per le regole specifiche di Coolify.
Coolify sullo stesso server: perché la validazione si rompe dopo una regola SSH solo-Tailscale
Tailscale non ha rotto Coolify. UFW (e una regola Hetzner equivalente) ha fatto esattamente quello che gli hai chiesto: permettere SSH solo dal range CGNAT di Tailscale (100.64.0.0/10) e da qualche altra fonte. L'accesso umano via Tailscale continua a funzionare.
Coolify valida il server aprendo una sessione SSH dall'interno di un container Docker (l'app Coolify, il sentinel, o servizi correlati). Quel traffico non arriva da 100.x.x.x. Arriva dalla rete Docker sull'host, ad esempio 10.0.1.x sulla rete coolify.
La sequenza è quindi questa:
- UFW:
2222/tcp ALLOW from 100.64.0.0/10solo. - Il container prova a raggiungere l'host sulla porta 2222 (per eseguire comandi remoti e validare Docker).
- La sorgente del pacchetto è
10.0.1.x(o un altro range Docker). UFW non ha una regola di allow per quella sorgente. - Risultato: connection timeout (pacchetto droppato), non "connection refused".
Perché 127.0.0.1 in Coolify fallisce: dentro al container, 127.0.0.1 è il container stesso, non la VPS. Lì non ascolta nessuno sulla 2222, quindi ottieni connection refused.
Perché 172.17.0.1 può fallire: quello è il gateway della rete bridge di default. Coolify spesso si attacca a una rete con nome (ad esempio coolify) con un gateway diverso (ad esempio 10.0.1.1). Il gateway che vedi da docker network inspect bridge può differire dal gateway che i container Coolify usano davvero.
Fix (sulla VPS, da una sessione SSH funzionante, ad esempio via Tailscale):
- Permetti alle sorgenti interne Docker di raggiungere SSH sull'host (stringi le subnet se preferisci):
sudo ufw allow from 10.0.0.0/8 to any port 2222 proto tcp comment 'Docker to host SSH'
sudo ufw allow from 172.16.0.0/12 to any port 2222 proto tcp comment 'Docker bridge ranges to host SSH'
sudo ufw reload
Usa la tua porta SSH reale al posto di 2222 se è diversa.
- Imposta Coolify → Servers → il tuo server → IP sul gateway della rete Docker
coolify(l'host visto da quei container), non127.0.0.1:
docker network inspect coolify --format '{{range .IPAM.Config}}Subnet: {{.Subnet}} Gateway: {{.Gateway}}{{"\n"}}{{end}}'
Pattern di esempio: gateway 10.0.1.1, subnet 10.0.1.0/24. Inserisci quel gateway in Coolify con User e Port che corrispondono a sshd sull'host.
- Salva in Coolify e Validate / Revalidate il server.
Riassunto: SSH solo-Tailscale su UFW è corretto per te. Coolify ha bisogno di un allow extra su UFW (e opzionalmente Hetzner) così che Docker → host:2222 sia permesso, più l'IP gateway della rete Docker in Coolify al posto di localhost.
Verifica finale
- Dalla sessione SSH Tailscale, esegui
ufw statuse conferma le regole. - Chiudi la sessione SSH su IP pubblico.
- Dalla tua macchina locale, fai SSH via Tailscale:
ssh [email protected]. Deve funzionare. - Prova SSH via IP pubblico. Deve essere rifiutato.
La tua VPS adesso è raggiungibile solo via Tailscale (per te) e Cloudflare (per il traffico web). Il resto di internet non si può collegare.
Perché conta
Una VPS con SSH e porte web aperte è un bersaglio. I bot scansionano l'intero spazio IPv4. Provano password di default, exploit noti e brute force. Bloccare SSH a Tailscale rimuove quella superficie. Bloccare 80/443 a Cloudflare significa che solo Cloudflare può raggiungere il tuo origin. Cloudflare gestisce DDoS, bot e traffico malevolo prima che arrivi al server.
Il tuo server diventa una macchina privata con cui solo tu e Cloudflare potete parlare. È così che dovrebbe essere.
Integrazione con lo script di setup
Lo script di Server Setup può installare e collegare Tailscale automaticamente. Passa la tua auth key:
TAILSCALE_AUTH_KEY=tskey-auth-xxxxxxxxxxxx ./server-setup.sh
Lo script installa Tailscale e lancia tailscale up. Stampa il tuo IP Tailscale alla fine. Apri un nuovo terminale, fai SSH su quell'IP, poi esegui il lockdown del firewall:
scp -P 2222 scripts/firewall-lockdown.sh deploy@YOUR_TAILSCALE_IP:~/
ssh -p 2222 deploy@YOUR_TAILSCALE_IP
chmod +x ~/firewall-lockdown.sh
./firewall-lockdown.sh
Lo script firewall-lockdown.sh restringe UFW a Tailscale (SSH) e Cloudflare (80/443). Eseguilo solo da una sessione Tailscale. Imposta SSH_PORT=2222 se la tua porta SSH è diversa.
Per Hetzner Cloud Firewall: durante il setup iniziale potresti aver bisogno di SSH (22 o 2222) aperto da Any per poterti collegare. Dopo che Tailscale funziona, cambia la regola per permettere solo 100.64.0.0/10 (range Tailscale).