Come configurare un subnet router Tailscale su VPS
Guida per annunciare una rete privata dal VPS al tailnet: approva le route, rendi persistente l'IP forwarding e usa --accept-routes su Linux.
Cosa fa un subnet router Tailscale
Un subnet router Tailscale è una macchina che annuncia al tuo tailnet un intero intervallo di indirizzi IP privati, così ogni dispositivo del tailnet può raggiungere gli indirizzi di quell'intervallo anche se nessun dispositivo al suo interno esegue Tailscale. Il tailnet è la tua rete privata Tailscale: l'insieme dei dispositivi autenticati con lo stesso account o appartenenti alla stessa organizzazione. La funzionalità che viene spesso confusa con il subnet router è l'exit node, che svolge il compito opposto. Invia tutto il traffico di un dispositivo attraverso il VPS, quindi il VPS diventa il percorso usato da quel dispositivo per raggiungere Internet.
Una frase per ciascun concetto. Un subnet router rende una rete privata raggiungibile dal tailnet. Un exit node modifica il punto da cui il traffico pubblico esce verso Internet. Se è questo ciò che ti serve, consulta invece come eseguire un exit node Tailscale su un VPS. Sono opzioni separate e un VPS può svolgere entrambe le funzioni contemporaneamente, ma risolvono problemi diversi e possono non funzionare per motivi diversi.
Quando un VPS deve fungere da subnet router
Il caso più comune riguarda una rete privata già fornita dal provider. Il VPS ha un indirizzo pubblico e una seconda interfaccia su un segmento privato, mentre gli altri server di quel segmento non hanno alcun indirizzo pubblico: un database all'indirizzo 10.0.0.20 e una destinazione per i backup all'indirizzo 10.0.0.30. Installate Tailscale su un VPS e pubblicizzate 10.0.0.0/24. Il laptop potrà raggiungere direttamente quegli indirizzi privati. Non cambia nulla sugli altri host del segmento e il database continua a non avere un indirizzo pubblico.
L'altro caso riguarda una rete situata oltre il VPS. Può essere una LAN domestica o aziendale dietro il proprio router, oppure un rack di appliance che non possono eseguire Tailscale, ad esempio uno switch gestito o un vecchio NAS con firmware bloccato. Un sistema Linux presente su quella rete diventa il subnet router per tutti gli altri dispositivi della rete.
Entrambi i casi hanno lo stesso requisito. Il subnet router deve poter raggiungere autonomamente l'intervallo che pubblicizza, usando la propria tabella di routing e il proprio firewall. Tailscale non crea questa connettività. Trasporta il traffico fino al router e lo passa al kernel, che lo inoltra.
Installare Tailscale e verificare prima la route locale
curl -fsSL https://tailscale.com/install.sh | shLo script rileva la distribuzione, aggiunge il repository dei pacchetti di Tailscale, installa il comando tailscale e il daemon tailscaled, quindi abilita il servizio. Verificare con systemctl is-active tailscaled: dovrebbe visualizzare active.
Prima di procedere, verificare che il VPS possa raggiungere la rete che si intende pubblicizzare.
ip route show
ping -c3 10.0.0.20ip route show deve elencare l'intervallo privato su un'interfaccia reale, ad esempio 10.0.0.0/24 dev enp7s0 proto kernel scope link src 10.0.0.5. Se il ping fallisce in questo punto, direttamente sul router, nessun flag di Tailscale può risolvere il problema. La causa è nella configurazione di rete del VPS oppure in un firewall sull'host di destinazione. Risolvere prima questo problema, perché tutti i test successivi dipendono da questa connettività.
Attivare l'inoltro IP e mantenerlo dopo un riavvio
Una macchina Linux scarta tutti i pacchetti non indirizzati a se stessa se l'inoltro non è attivo. Inoltrare i pacchetti di altre macchine è la funzione principale di un router di subnet, quindi questo passaggio è obbligatorio.
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.confVerificarlo con sysctl net.ipv4.ip_forward, che dovrebbe stampare net.ipv4.ip_forward = 1.
Spesso questo passaggio viene completato solo parzialmente. sudo sysctl -w net.ipv4.ip_forward=1 funziona immediatamente, ma la modifica viene persa al riavvio successivo. Di conseguenza, il router di subnet può funzionare per settimane e poi smettere di inoltrare il traffico la mattina dopo un riavvio dovuto a un aggiornamento del kernel. L'aspetto fuorviante è che nulla sembra non funzionare. tailscale status mostra ancora il nodo come online, la console di amministrazione indica ancora che la route è approvata e i client hanno ancora la route installata. I pacchetti arrivano al VPS, ma il kernel li scarta senza registrare alcun messaggio. Scrivere i valori in /etc/sysctl.d/99-tailscale.conf consente di ripristinarli dopo un riavvio.
Se si pubblicizzano le route mentre l'inoltro è ancora disattivato, tailscale up mostra un avviso al momento dell'operazione, con una riga simile a Warning: IPv4 forwarding is disabled. Subnet routes and exit nodes may not work correctly.. Leggere l'output di quel comando invece di ignorarlo.
Pubblicizzare le route
sudo tailscale up --advertise-routes=10.0.0.0/24Su un VPS già connesso al proprio tailnet, modificare invece l'impostazione esistente:
sudo tailscale set --advertise-routes=10.0.0.0/24Usare tailscale set per ogni modifica successiva. Eseguire di nuovo tailscale up con un solo flag reimposta i flag non specificati. La CLI interrompe l'operazione con un errore che indica che, per modificare le impostazioni in questo modo, è necessario specificare tutti i flag non predefiniti. tailscale set modifica una sola impostazione e lascia invariate le altre.
Più intervalli devono essere indicati in un unico elenco separato da virgole, senza spazi: --advertise-routes=10.0.0.0/24,192.168.50.0/24. Ogni voce deve essere un indirizzo di rete in notazione CIDR (classless inter-domain routing, nel formato 10.0.0.0/24). Se si indica per errore il proprio indirizzo host, 10.0.0.5/24, l'operazione viene rifiutata perché i bit dopo il prefisso non sono impostati a zero. L'errore indica il prefisso probabilmente desiderato. Per interrompere la pubblicizzazione, impostare un elenco vuoto con sudo tailscale set --advertise-routes=.
Approva la route nella console di amministrazione
La pubblicazione di una route è una richiesta, non una modifica immediata. Finché un amministratore non la approva, nessun client riceve la route e nulla nell'intervallo è raggiungibile. Questo comportamento è intenzionale: una macchina che può aggiungersi alla tabella di routing di tutti potrebbe intercettare il traffico di qualsiasi intervallo scelto.
Approvala nella pagina Machines della console di amministrazione. Il VPS è indicato con un badge subnet. Apri la relativa riga, individua la sezione delle subnet, modifica le impostazioni della route, seleziona la route e salva.
L'approvazione è specifica per ogni prefisso. Pubblica 10.0.0.0/24 oggi e 192.168.50.0/24 il mese prossimo: il nuovo prefisso viene aggiunto senza approvazione, mentre quello precedente continua a funzionare. Dal VPS, una route approvata e una route ignorata hanno lo stesso aspetto. Controlla quindi la console prima di eseguire altri controlli.
Puoi saltare il passaggio manuale con un blocco autoApprovers nel file delle policy della tailnet:
{
"autoApprovers": {
"routes": {
"10.0.0.0/24": ["tag:subnet-router"]
}
}
}Poi avvia il nodo con quel tag, sudo tailscale up --advertise-routes=10.0.0.0/24 --advertise-tags=tag:subnet-router, e la route viene approvata non appena viene pubblicata. Il tag deve esistere prima nella sezione tagOwners dello stesso file delle policy. Questa configurazione è utile se ricrei il VPS tramite uno script, perché un nodo ricreato è un nuovo nodo e le sue route tornano a essere non approvate.
Perché i client Linux ignorano la route senza --accept-routes
La route è stata pubblicizzata e approvata. Il telefono e il Mac possono raggiungere 10.0.0.20. Il laptop Linux non può farlo e nella console di amministrazione non compare alcun problema.
Accettare una route di subnet significa scrivere le relative voci nella tabella di routing del client. Su Android, iOS, macOS, tvOS e Windows, il client Tailscale esegue questa operazione automaticamente. Su Linux non avviene, perché una macchina Linux è spesso un server o un router con una tabella di routing configurata intenzionalmente. L'inserimento silenzioso di una /24 appresa dalla rete potrebbe interrompere il traffico che la macchina gestisce già. Per questo, su Linux è necessario abilitare esplicitamente l'opzione su ogni client:
sudo tailscale set --accept-routesQuindi verifica dove è stata inserita la route:
ip route show table 52
ip route get 10.0.0.20Su Linux, Tailscale non inserisce le route accettate nella tabella di routing principale. Le inserisce nella tabella di routing 52 e installa regole di policy, visibili con ip rule show nell'intervallo di priorità da 5210 a 5270, che inoltrano a questa tabella i pacchetti non corrispondenti ad altre regole. Di conseguenza, ip route show da solo non elencherà mai 10.0.0.0/24 e chi controlla soltanto questo comando conclude che --accept-routes non ha prodotto alcun effetto. ip route show table 52 è il comando che mostra la situazione reale e dovrebbe elencare l'intervallo pubblicizzato su tailscale0.
È utile conoscere un'eccezione. Se questo nodo Linux è anche un secondo subnet router per la propria rete locale, --accept-routes lo fa instradare il traffico destinato alla subnet direttamente connessa attraverso l'altro router, invece che attraverso la propria interfaccia. Su un router standby appartenente a una coppia ad alta disponibilità, lascia --accept-routes disattivato e limita la configurazione alla pubblicizzazione delle route.
Modalità di errore: due router che pubblicizzano intervalli sovrapposti
Due subnet router non devono pubblicizzare intervalli identici. Gli intervalli sovrapposti con lunghezze di prefisso diverse sono consentiti e Tailscale seleziona la corrispondenza più specifica. Se il router A pubblicizza 10.0.0.0/24 e il router B pubblicizza 10.0.0.0/16, il traffico diretto a 10.0.0.20 passa da A.
Il comportamento che sorprende è quello che si verifica quando A va offline. Tailscale non passa automaticamente alla route meno specifica. Il traffico verso 10.0.0.20 si interrompe, mentre quello verso 10.1.0.20 continua a funzionare tramite B. Il sintomo sembra indicare che metà della rete privata non sia disponibile, ma la causa è un nodo offline che mantiene il prefisso più specifico. Per ottenere il failover, configura anche il router con l'intervallo più ampio in modo che pubblicizzi i prefissi più stretti. In questo modo entrambi coprono gli stessi indirizzi.
L'altra sovrapposizione si verifica più vicino al client. Se sei connesso a una rete dell'hotel su 192.168.1.0/24 mentre il tuo subnet router pubblicizza 192.168.1.0/24, le due route competono per le stesse destinazioni e la scelta dipende dalla piattaforma. Su Linux, installa una regola con priorità superiore a quella usata da Tailscale, in modo che gli indirizzi locali utilizzino la tabella principale:
sudo ip rule add to 192.168.1.0/24 priority 2500 lookup mainLa regola non è persistente e viene rimossa al successivo avvio. La soluzione corretta consiste nello scegliere un intervallo privato che non incontrerai normalmente su altre reti. 192.168.0.0/24 e 192.168.1.0/24 sono i valori predefiniti sulla maggior parte dei router domestici; scegli quindi un intervallo all'interno di 10.0.0.0/8 definito intenzionalmente. La stessa collisione interrompe anche una VPN WireGuard standard configurata manualmente, per lo stesso motivo: la route locale più specifica ha la precedenza e il traffico non entra mai nel tunnel.
Modalità di errore: il DNS risolve un indirizzo che nessuna route copre
Questo problema è difficile da diagnosticare perché nulla segnala un errore. Il nome viene risolto, ma la connessione va in timeout.
Supponiamo che db.internal.example.com venga risolto in 10.0.5.20 tramite il tuo nameserver privato e che tu abbia pubblicizzato 10.0.0.0/24. La query ha esito positivo perché la risoluzione DNS (domain name system) e il routing IP sono passaggi distinti e nessuno dei due verifica l'altro. Il pacchetto destinato a 10.0.5.20 non trova quindi una route corrispondente sul tailnet, esce dal default gateway del client e va perso.
Due comandi consentono di separare i due aspetti:
nslookup db.internal.example.com
ip route get 10.0.5.20Se la query restituisce un indirizzo ma ip route get non risponde con dev tailscale0, il nome è corretto e manca la route. Pubblicizza un intervallo che includa l'indirizzo, usando 10.0.0.0/16 oppure un secondo prefisso esplicito, quindi approva il nuovo prefisso nella console.
Esiste un problema analogo sul nameserver stesso. Se imposti nella console di amministrazione un nameserver globale a un indirizzo privato come 10.0.0.53, tale indirizzo deve trovarsi all'interno di una route approvata; in caso contrario, i dispositivi non possono raggiungere il resolver. Se attivi l'opzione che sostituisce i server DNS locali puntando a un resolver irraggiungibile, tutti i dispositivi del tailnet perdono immediatamente la risoluzione dei nomi, compresi quelli che funzionavano un secondo prima. Pubblicizza e approva prima la route verso il resolver, quindi modifica l'impostazione DNS. Se continui ad avere problemi con il DNS all'interno di un tunnel, il funzionamento del DNS quando si interrompe su un tunnel WireGuard descrive lo stesso meccanismo senza il livello di coordinamento aggiuntivo.
NAT del sorgente e collegamenti site-to-site
Per impostazione predefinita, il subnet router riscrive l'indirizzo sorgente di ogni pacchetto inoltrato sostituendolo con il proprio indirizzo privato. Questa operazione è SNAT (source network address translation) e consente alle risposte di funzionare senza modificare la rete privata: il database all'indirizzo 10.0.0.20 risponde al VPS, che sa già come raggiungere. Lo svantaggio è che il database vede ogni connessione tailnet come proveniente dal VPS. Di conseguenza, le regole del firewall basate sulla sorgente e i log degli accessi non forniscono informazioni utili.
Disattivala su Linux quando vuoi mantenere l'indirizzo tailnet reale del client:
sudo tailscale set --snat-subnet-routes=falseGli host della rete privata devono quindi disporre di una route verso 100.64.0.0/10, l'intervallo che Tailscale assegna ai dispositivi, con il subnet router come gateway. Senza questa route di ritorno, le risposte vengono inviate al gateway predefinito e non arrivano mai a destinazione. Le connessioni quindi restano bloccate dopo il primo pacchetto. Aggiungi la route statica al gateway della rete privata oppure lascia SNAT attivo.
Un collegamento site-to-site usa due subnet router contemporaneamente. Ciascuno pubblicizza la propria rete e accetta quella dell'altro:
sudo tailscale up --advertise-routes=10.0.0.0/24 --snat-subnet-routes=false --accept-routesEsegui il comando corrispondente sull'altro router, usando il relativo intervallo. I due intervalli devono essere diversi. Se i trasferimenti di grandi dimensioni si bloccano, mentre ssh e ping funzionano, la causa è MSS (maximum segment size), cioè la dimensione massima dei dati trasportati da un pacchetto TCP. L'overhead del tunnel rende i pacchetti inoltrati troppo grandi per uno dei collegamenti intermedi. Il clamping risolve il problema:
sudo iptables -t mangle -A FORWARD -o tailscale0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtuSalva la regola con iptables-persistent, altrimenti scompare al successivo avvio.
Manutenzione per mantenerlo operativo
Le chiavi dei nodi scadono per impostazione predefinita dopo 180 giorni, a partire da agosto 2026. Quando scade la chiave di un router di subnet, il nodo viene disconnesso e l'intero intervallo pubblicizzato diventa irraggiungibile, senza che una modifica alla configurazione lo spieghi. Disabilita la scadenza delle chiavi per questa macchina nella pagina Machines della console di amministrazione, quindi annota di averlo fatto.
Tailscale preferisce una connessione diretta tra i peer e ricorre ai propri server relay quando non riesce a stabilirne una. I relay funzionano, ma aggiungono latenza. Un VPS con un indirizzo pubblico è il caso più semplice: consenti il traffico UDP in ingresso sulla porta 41641 e la maggior parte dei peer si connetterà direttamente. Se il firewall è gestito da ufw, le regole ufw effettivamente necessarie su un VPS illustrano la sintassi.
Le regole di accesso sono l'altra parte. In un tailnet predefinito, ogni tuo dispositivo può raggiungere tutti gli altri, quindi una route approvata funziona immediatamente. Dopo aver scritto una policy ACL, il campo di destinazione di una regola deve indicare l'intervallo privato, perché 10.0.0.20 non è un indirizzo tailnet e non è incluso nelle regole scritte per gli indirizzi IP tailnet o per i tag.
Infine, decidi se vuoi usare un coordination server che non gestisci direttamente. Il control plane di Tailscale è un servizio hosted. Le chiavi restano sulle tue macchine, ma l'account e il file della policy risiedono sul servizio. Eseguire Headscale, il control server Tailscale self-hosted mantiene questi componenti sul tuo VPS, al costo di doverli gestire. L'altra risposta alla stessa esigenza consiste nel non usare nemmeno i client Tailscale e nel self-hosting del server VPN NetBird, che colloca il coordination layer e i relativi client mesh su una macchina sotto il tuo controllo. Se stai ancora scegliendo tra questo modello e una configurazione scritta manualmente, il confronto tra WireGuard e Tailscale spiega cosa offre il coordination layer e quali costi comporta.
FAQ
Qual è la differenza tra un subnet router e un exit node?
Un subnet router pubblicizza un intervallo di indirizzi privati, consentendo ai dispositivi della tailnet di raggiungere macchine su cui Tailscale non è in esecuzione. Un exit node si pubblicizza come route per l'intera Internet, quindi un dispositivo invia tutto il proprio traffico tramite l'indirizzo pubblico di quel nodo. Un singolo VPS può svolgere entrambi i ruoli. Sono flag distinti, --advertise-routes e --advertise-exit-node, e ciascuno richiede un'approvazione separata nella console di amministrazione.
Perché il mio client Linux ignora la subnet route pubblicizzata?
I client Linux non accettano le subnet route finché non lo si richiede esplicitamente. Esegui sudo tailscale set --accept-routes sul client. Poi verifica con ip route show table 52, non con ip route show. Tailscale installa le route accettate nella routing table 52 e le utilizza tramite policy rules, quindi la main table non le elenca e una route funzionante può sembrare assente.
La subnet ha smesso di funzionare dopo un riavvio. Che cosa si è guastato?
Molto probabilmente l'IP forwarding. Un valore impostato con sysctl -w non sopravvive a un riavvio, quindi scrivilo in /etc/sysctl.d/99-tailscale.conf e confermalo con sysctl net.ipv4.ip_forward. Se il forwarding è attivo e l'intervallo è ancora irraggiungibile, controlla il nodo nella console di amministrazione. Per impostazione predefinita, le node key scadono dopo 180 giorni; un subnet router con una chiave scaduta sembra quindi causare un problema di rete, non un problema dell'account.
Due subnet router possono pubblicizzare lo stesso intervallo?
Non intervalli identici. Gli intervalli sovrapposti con lunghezze di prefisso diverse sono supportati e prevale quello più specifico. Il failover richiede attenzione: quando il router che gestisce il prefisso più specifico va offline, Tailscale non utilizza automaticamente la route più ampia, quindi il traffico si interrompe. Per una coppia realmente ridondata, configura entrambi i router affinché pubblicizzino gli stessi prefissi specifici.
Il nome host viene risolto, ma la connessione va in timeout. Perché?
La risoluzione DNS e il routing sono fasi separate. Un nome può essere risolto in un indirizzo non coperto da alcuna route approvata; in questo caso il pacchetto esce tramite il default gateway del client. Esegui ip route get <address> sul client. Se la risposta non include dev tailscale0, pubblicizza un intervallo che includa quell'indirizzo e approva il nuovo prefisso nella console di amministrazione.