Come aggiungere l’header Onion-Location in nginx
Configura Onion-Location in nginx perché Tor Browser proponga il tuo indirizzo onion. Verifica redirect e risorse di terze parti per evitare perdite di privacy.
Cosa fa l’header Onion-Location
L’header Onion-Location è una riga nel vhost clearnet che comunica l’indirizzo onion al Tor Browser. Un visitatore che raggiunge https://example.com tramite Tor vede nella barra degli indirizzi un pulsante viola con il testo .onion available; con un clic passa al tuo onion service. È un meccanismo di rilevamento e non svolge altre funzioni. L’header non crea l’onion service e non nasconde alcuna informazione su di te.
Questa guida presuppone che entrambe le parti siano già disponibili. Hai un sito su un VPS dietro nginx e un onion service v3 funzionante che punta al sito. Se la seconda parte non è ancora pronta, configurala prima: pubblicare un sito onion su un VPS descrive le righe di torrc e il primo file hostname. Di seguito spieghiamo come collegare le due parti senza fare confluire l’una nell’altra.
Condizioni richieste da Tor Browser prima di applicare l'header
Il Tor Project documenta tre condizioni. Devono essere soddisfatte tutte; in caso contrario, il pill non viene mai visualizzato.
- Il valore
Onion-Locationdeve essere un URL valido con schemahttp:ohttps:e hostname.onion. - La pagina Web che definisce l'header deve essere pubblicata tramite HTTPS.
- La pagina Web che definisce l'header non deve essere essa stessa un sito onion.
La seconda condizione è quella che causa più problemi. La terza spiega perché non si imposta mai questo header sul virtual host onion. Esiste una quarta regola, non riportata nella documentazione descrittiva ma presente nell'implementazione: Tor Browser applica l'header solo al documento di primo livello. Prima di eseguire qualsiasi operazione, il codice confronta la destinazione del caricamento con il documento. Di conseguenza, un header restituito da un foglio di stile, un'immagine o una risposta API viene ignorato.
Per impostazione predefinita, il browser mostra il pill e attende un clic. Chi desidera un passaggio automatico deve attivare l'opzione in Settings, quindi Privacy and Security e Onion Services, impostando "Prioritize .onion sites when known" su "Always". Non è possibile forzare questo comportamento dal server. Considerate l'header come una proposta, non come un redirect.
Aggiungere l'header Onion-Location in nginx
L'header deve trovarsi nel blocco server che termina TLS per il dominio clearnet. Se lo inserisci invece nel blocco sulla porta 80, non accade nulla, perché quel blocco esegue soltanto un redirect e il requisito due esclude un header definito su una pagina HTTP non protetta.
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
add_header Onion-Location http://<your-onion-address>.onion$request_uri always;
root /srv/example.com/public;
}$request_uri contiene il percorso e la stringa di query, quindi a chi legge https://example.com/guides/tor viene proposto lo stesso percorso sul sito onion. Se lo ometti, ogni visitatore arriva alla home page onion invece che alla pagina che stava leggendo.
always è importante a causa di un limite documentato di nginx. add_header aggiunge il campo solo quando il codice della risposta è 200, 201, 204, 206, 301, 302, 303, 304, 307 o 308. La pagina 404 è un punto di accesso reale dai risultati di ricerca e, senza always, non contiene alcun header.
La seconda trappola di nginx riguarda l'ereditarietà e causa un errore silenzioso. Le direttive add_header vengono ereditate dal livello di configurazione precedente solo se al livello corrente non sono presenti direttive add_header. Di conseguenza, un blocco location /assets/ { add_header Cache-Control ...; } scarta Onion-Location definito a livello server per ogni URL al suo interno. Se imposti header specifici per le location, ripeti la riga Onion-Location all'interno di ciascuno di questi blocchi. Come nginx seleziona un blocco server e un blocco location merita una lettura se questo comportamento non ti è familiare.
Ricarica la configurazione e controlla una pagina normale e una inesistente:
sudo nginx -t && sudo systemctl reload nginx
curl -sI https://example.com/ | grep -i onion-location
curl -sI https://example.com/no-such-page | grep -i onion-locationEntrambi i comandi devono stampare una riga onion-location:. Il secondo comando dimostra che always funziona. Se il secondo comando non produce output, manca il flag oppure un blocco location sta rendendo inefficace la direttiva.
Il tag meta HTML quando non puoi impostare gli header
Gli host statici e alcune dashboard CDN non consentono di aggiungere un header di risposta arbitrario. Lo stesso valore può essere usato come elemento meta nell'head del documento, perché il browser legge questi dati dell'header del documento sia quando arrivano tramite HTTP sia quando sono contenuti in un tag http-equiv.
<meta http-equiv="onion-location" content="http://<your-onion-address>.onion" />I tre requisiti restano validi. La pagina che contiene il tag deve essere servita tramite HTTPS e non deve essere un onion. La differenza è che il tag contiene un unico indirizzo fisso senza percorso, perché non esiste una variabile lato server da espandere. Ogni pagina che lo contiene offre la home page onion. Questo è il costo del fallback, quindi preferisci l'header quando hai il controllo del server.
Servire il sito onion dal proprio vhost nginx
Il sito clearnet e quello onion non devono condividere lo stesso blocco server. Tor Browser invia Host: <your-onion-address>.onion. Se nessun blocco server dichiara quel nome, nginx ricade sul server predefinito, che corrisponde al vhost clearnet, e ogni URL generato da quel vhost contiene il nome del dominio.
Configurare il servizio nascosto su una porta a cui risponde soltanto l'interfaccia loopback:
HiddenServiceDir /var/lib/tor/onion_site/
HiddenServicePort 80 127.0.0.1:8080Assegnare quindi a quella porta un vhost dedicato:
server {
listen 127.0.0.1:8080;
server_name <your-onion-address>.onion;
absolute_redirect off;
port_in_redirect off;
root /srv/example.com/public;
}listen 127.0.0.1:8080 impedisce a questo vhost di essere raggiungibile dall'IP pubblico. In questo modo chi esegue una scansione sull'indirizzo del VPS non può recuperarlo e confrontarlo byte per byte con la copia clearnet. absolute_redirect off fa sì che nginx generi valori Location relativi. Di conseguenza, il redirect con slash finale per una directory restituisce Location: /guides/ invece di un URL completo. nginx costruisce già i redirect assoluti usando l'header Host, non server_name, perché server_name_in_redirect ha come valore predefinito off. Un redirect relativo elimina comunque ogni ambiguità.
Perché la pagina onion continua a reindirizzare i visitatori al sito clearnet?
Nginx raramente è la causa della fuga. Lo è l'applicazione. Qualsiasi componente che costruisce un URL assoluto a partire dall'indirizzo del sito configurato userà il vostro dominio, indipendentemente dal vhost che ha gestito la richiesta.
- Un tag link
rel="canonical"che punta ahttps://example.com/.... È il caso più comune e rivela l'URL esatto della pagina clearnet a chi visualizza il codice sorgente. - Redirect generati dal framework invece che da nginx, ad esempio l'opzione
SECURE_SSL_REDIRECTdi Django oppure le opzionihomeesiteurldi WordPress. og:urle gli altri meta tag per le schede social.- Voci della sitemap e del feed RSS, che per specifica sono assolute.
- Pagine di errore dell'applicazione, che di solito includono un link "torna alla home page" costruito a partire dalla stessa impostazione.
La correzione dipende dallo stack in uso e non esiste una soluzione generica. Il controllo, invece, è generico. Recuperate la pagina onion tramite Tor e cercate il vostro dominio nella risposta.
curl -s --socks5-hostname 127.0.0.1:9050 http://<your-onion-address>.onion/ \
| grep -i 'example\.com'--socks5-hostname invia il nome alla porta SOCKS di Tor per la risoluzione, necessaria perché nulla sul vostro computer può risolvere localmente un nome .onion. La porta 9050 è quella predefinita per un demone Tor installato tramite pacchetto. Un risultato vuoto indica che il controllo è superato. Qualsiasi corrispondenza identifica una pagina che espone il dominio clearnet a ogni visitatore onion. Eseguite il controllo sulla home page e poi su un URL che restituisce un 404.
Controllate separatamente la catena di redirect, perché il corpo di una risposta di redirect è solitamente vuoto:
curl -sI --socks5-hostname 127.0.0.1:9050 http://<your-onion-address>.onion/guides \
| grep -i '^location'Un valore Location che indica example.com significa che un redirect sta riportando il visitatore onion sulla rete clearnet tramite un exit node, in risposta a una richiesta che il visitatore riteneva sarebbe rimasta all'interno di Tor.
Non presentare il certificato clearnet sull’onion
Un indirizzo onion v3 deriva dalla chiave pubblica del servizio. Tor autentica e cifra il circuito verso quello specifico servizio prima di inviare qualsiasi richiesta HTTP. L’HTTP non cifrato all’interno di un onion service è la configurazione normale. Non equivale all’HTTP non cifrato su Internet.
Se si crea il virtual host onion copiando quello clearnet, si copia anche ssl_certificate. A quel punto l’onion presenta un certificato i cui Subject Alternative Name includono example.com. Si verificano due problemi. Il browser segnala una mancata corrispondenza del nome, perché l’URL è l’indirizzo onion e il certificato non lo copre. Inoltre, ogni visitatore che prosegue nonostante l’avviso riceve un’attestazione firmata del fatto che i due siti appartengono alla stessa macchina. Mantieni il virtual host onion in un file separato con il proprio server_name. In questo modo resta anche separato dal plugin Nginx di Certbot, che modifica il blocco server corrispondente al dominio per cui richiedi un certificato.
Quale pacchetto tor usare e come proteggere la chiave del servizio
Il pacchetto tor disponibile nell'archivio Ubuntu è adatto a questo scopo e non richiede configurazioni aggiuntive. È però indietro rispetto alla serie stabile corrente. Per un servizio che prevedi di mantenere attivo, usa il repository Debian ufficiale di Tor Project e lascia che apt lo aggiorni insieme agli altri pacchetti. Ad agosto 2026, i passaggi documentati sono i seguenti:
sudo apt install apt-transport-https
wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc \
| gpg --dearmor \
| sudo tee /usr/share/keyrings/deb.torproject.org-keyring.gpg >/dev/nullScrivi /etc/apt/sources.list.d/tor.sources, sostituendo la suite con il codename della tua release ricavato da lsb_release -c:
Types: deb deb-src
URIs: https://deb.torproject.org/torproject.org/
Suites: noble
Components: main
Signed-By: /usr/share/keyrings/deb.torproject.org-keyring.gpgsudo apt update
sudo apt install tor deb.torproject.org-keyringIl pacchetto deb.torproject.org-keyring mantiene aggiornata la chiave di firma, così il repository continuerà a superare la verifica anche tra un anno. Scegli una sola origine e mantienila. Il pacchetto dell'archivio e quello del repository hanno versioni diverse. Se entrambi sono abilitati, apt può spostarti dall'uno all'altro durante gli aggiornamenti.
La directory HiddenServiceDir contiene l'identità del servizio. Il file hs_ed25519_secret_key in quella directory è l'indirizzo onion del servizio, perché l'indirizzo è la metà pubblica di quella coppia di chiavi. Se perdi il file, l'indirizzo è perso in modo permanente, perché non esiste un'autorità che possa rigenerarlo. Se copi il file in un luogo non protetto, chiunque ne possieda una copia può eseguire il tuo servizio onion.
tor rifiuta di usare una directory leggibile da altri utenti. Controlla prima i permessi e il proprietario:
sudo ls -ld /var/lib/tor/onion_site
sudo -u debian-tor cat /var/lib/tor/onion_site/hostnameL'output dovrebbe essere drwx------, con proprietario e gruppo debian-tor su Debian e Ubuntu. Se i permessi sono più ampi, tor registra una riga simile a Permissions on directory /var/lib/tor/onion_site/ are too permissive. e il servizio non si avvia. Correggi la situazione con sudo chown -R debian-tor:debian-tor /var/lib/tor/onion_site seguito da sudo chmod 700 /var/lib/tor/onion_site, riavvia con sudo systemctl restart tor e verifica il risultato con sudo journalctl -u tor@default -n 30.
Esegui il backup di quella directory come faresti con una chiave privata: fuori dal server e in forma cifrata. Non inserirla mai nel repository che contiene il sito. Se lo stesso server deve anche consentire l'accesso amministrativo tramite Tor, raggiungere SSH tramite un servizio onion garantisce una separazione più pulita rispetto all'esposizione di un percorso di gestione sul sito pubblico.
Analytics e risorse di terze parti espongono più informazioni dell'header
Questa è la parte più importante e non riguarda Onion-Location. Ogni risorsa di terze parti referenziata dalla pagina genera una richiesta che il browser del visitatore invia dall'onion verso la clearnet tramite un exit node. Un font ospitato su un CDN pubblico, uno script di analytics esterno, un lettore video incorporato o un widget per i commenti comunicano a quel soggetto che qualcuno sta caricando la pagina in una sessione instradata deliberatamente tramite Tor.
Le conseguenze sono due. Il soggetto terzo viene a conoscenza della visita. Inoltre, poiché la copia clearnet carica le stesse risorse dagli stessi provider, chiunque possa osservare uno dei due lati può associare le due proprietà senza difficoltà.
Servi tutto dalla stessa origine. Ospita direttamente i font. Rimuovi il tag di analytics esterno oppure spostalo sul tuo server, dove l'analytics self-hosted su un VPS mantiene la richiesta all'interno dell'onion. Considera che le impostazioni predefinite di Tor Browser bloccano o limitano gran parte dei dati che qualsiasi strumento di analytics prova a raccogliere. È il comportamento corretto. Se una pagina non può funzionare senza uno script di terze parti, non pubblicarla sull'onion.
Elenca ciò che una pagina scarica effettivamente:
curl -s --socks5-hostname 127.0.0.1:9050 http://<your-onion-address>.onion/ \
| grep -oE '(src|href)="https?://[^"]+"' | sort -uOgni riga stampata da questo comando è un URL assoluto che la pagina chiede al browser di recuperare. Qualsiasi URL che non corrisponde al tuo indirizzo onion genera una richiesta in uscita verso la clearnet che stai chiedendo ai lettori di effettuare per tuo conto.
Il modello delle minacce, in termini chiari
Onion-Location rende facile trovare un onion service, e fa soltanto questo. Non rende anonimo te, in qualità di operatore, perché il tuo dominio clearnet conserva comunque i dati del registrar, i record DNS, un certificato pubblicato nei log di Certificate Transparency e un account VPS associato ai tuoi dati di fatturazione. Non rende anonimo neppure l’onion service, perché hai appena pubblicato da quel dominio clearnet una dichiarazione pubblica e duratura secondo cui i due indirizzi corrispondono allo stesso sito. Il vantaggio riguarda il lettore: chi arriva tramite Tor può restare all’interno di Tor, senza alcun exit node nel percorso e senza eseguire una ricerca DNS per il tuo dominio. Se il tuo obiettivo è un onion service che non consenta a nessuno di collegarti a esso, non pubblicare questo header e non eseguire le due copie sulla stessa macchina.
In questo contesto emergono due domande correlate, e ciascuna ha una risposta specifica. La differenza tra Tor e una VPN determina cosa usi per il tuo traffico, una decisione separata rispetto a ciò che pubblichi. Inoltre, se i lettori di una rete soggetta a censura non possono raggiungere affatto il sito clearnet, non vedranno mai l’header; in questo caso bridge e pluggable transport sono più importanti di qualsiasi altro elemento descritto in questa pagina.
Verifica l’intera configurazione
Esegui questi comandi nell’ordine indicato. Ognuno produce un risultato verificabile.
curl -sI https://example.com/ | grep -i onion-locationstampa l’header.- Lo stesso comando eseguito su un URL che restituisce 404 stampa comunque l’header.
curl -s --socks5-hostname 127.0.0.1:9050 http://<your-onion-address>.onion/restituisce la pagina.- Cercando il dominio clearnet nell’output non viene restituito alcun risultato.
- Tor Browser su
https://example.commostra il contrassegno.onion available.
Se i passaggi da 1 a 4 hanno esito positivo e il passaggio 5 no, nella maggior parte dei casi il problema riguarda il punto da cui viene servito l’header, non l’header in sé. Verifica che il browser abbia realmente caricato la pagina HTTPS e non un redirect memorizzato nella cache, quindi esegui curl -sI sull’URL esatto che hai aperto, perché un blocco location applicato a quel percorso specifico potrebbe ignorare la direttiva definita a livello di server.
FAQ
Perché Tor Browser non mostra l'indicatore ".onion disponibile"?
Controlla prima i tre requisiti documentati. Il valore deve essere un URL completo con schema http: o https: e host .onion. Un indirizzo privo di schema quindi non funziona e non genera errori. La pagina deve essere servita tramite HTTPS. Un header configurato nel blocco di redirect sulla porta 80 non viene quindi mai letto. Inoltre, la pagina non deve essere un onion. Controlla poi nginx: qualsiasi add_header nel blocco location corrispondente elimina tutti gli add_header definiti a livello server. Senza il flag always, l'header non viene incluso nelle risposte 404 e 500. Esegui curl -sI sull'URL esatto che hai caricato nel browser e verifica che l'header sia effettivamente presente nella risposta trasmessa.
Ho bisogno di un certificato TLS per il mio sito onion?
No. Un indirizzo onion v3 deriva dalla chiave pubblica del servizio. Il circuito viene quindi autenticato per quello specifico servizio e cifrato end-to-end prima dell'invio di qualsiasi richiesta HTTP. HTTP in chiaro all'interno di un onion service è la configurazione normale. Devi invece evitare di presentare sull'onion il certificato del sito clearnet. Il relativo elenco dei subject alternative name contiene il tuo dominio. Questo attiva nel browser un avviso di mancata corrispondenza del nome e conferma a ogni visitatore che i due siti sono eseguiti sulla stessa macchina.
La pubblicazione di Onion-Location rende anonimo il mio sito?
No. L'header è una dichiarazione pubblica del tuo dominio clearnet: indica che un determinato indirizzo onion ti appartiene e chiunque può recuperarlo. Il vantaggio riguarda il lettore, che può passare all'onion ed eliminare dal percorso il nodo di uscita e la risoluzione DNS. In qualità di operatore non ottieni alcun anonimato e colleghi permanentemente i due indirizzi. Un onion service che non deve essere riconducibile a te deve essere pubblicato altrove, su hardware che non condivida nulla con il sito clearnet.
Posso usare il meta tag invece dell'header HTTP?
Sì, quando non puoi impostare gli header della risposta, come accade di norma su un host statico. Inserisci <meta http-equiv="onion-location" content="http://youraddress.onion" /> nell'head del documento. Si applicano gli stessi tre requisiti: la pagina deve usare HTTPS e non deve essere un onion. L'unica differenza sostanziale è che il tag contiene un indirizzo fisso senza percorso, mentre l'header nginx può aggiungere $request_uri e offrire al visitatore la stessa pagina sull'onion invece della home page.