Configurer Onion-Location dans nginx pour Tor Browser
Ajoutez Onion-Location dans nginx pour proposer l’adresse onion dans Tor Browser, puis évitez les fuites liées aux redirections et aux ressources tierces.
Fonctionnement de l’en-tête Onion-Location
L’en-tête Onion-Location est une ligne de votre vhost clearnet qui indique votre adresse onion à Tor Browser. Un visiteur qui accède à https://example.com avec Tor voit un bouton violet dans la barre d’adresse, libellé .onion available. Un clic le redirige vers votre service onion. Il s’agit uniquement d’un mécanisme de découverte. Cet en-tête ne crée pas le service onion et ne masque aucune information vous concernant.
Ce guide part du principe que les deux parties existent déjà. Vous avez un site sur un VPS derrière nginx et un service onion v3 fonctionnel qui pointe vers ce site. Si la seconde partie n’est pas encore en place, configurez-la d’abord : héberger un site onion sur un VPS explique les lignes torrc et le premier fichier hostname. La suite explique comment relier les deux sans exposer l’un dans l’autre.
Conditions requises par Tor Browser avant la prise en compte de l’en-tête
Le Tor Project documente trois conditions. Elles doivent toutes être remplies, sinon la pastille n’apparaît jamais.
- La valeur de
Onion-Locationdoit être une URL valide avec un schémahttp:ouhttps:et un nom d’hôte.onion. - La page web qui définit l’en-tête doit être servie via HTTPS.
- La page web qui définit l’en-tête ne doit pas être elle-même un site onion.
C’est la deuxième condition qui pose le plus souvent problème. La troisième explique pourquoi vous ne devez jamais définir cet en-tête sur le vhost onion. Il existe une quatrième règle, absente de la documentation rédigée mais présente dans l’implémentation : Tor Browser ne traite l’en-tête que pour le document de niveau supérieur. Le code compare la cible du chargement avec le document avant toute action. Un en-tête renvoyé par une feuille de style, une image ou une réponse d’API est donc ignoré.
Par défaut, le navigateur affiche la pastille et attend un clic. Pour activer une redirection automatique, l’utilisateur doit ouvrir Settings, puis Privacy and Security, puis Onion Services, et définir « Prioritize .onion sites when known » sur « Always ». Vous ne pouvez pas imposer ce comportement côté serveur. Considérez cet en-tête comme une proposition, pas comme une redirection.
Ajouter l’en-tête Onion-Location dans nginx
L’en-tête doit être défini dans le bloc server qui termine TLS pour votre domaine clearnet. Si vous le placez dans le bloc du port 80, rien ne se passe, car ce bloc se contente d’effectuer une redirection et la règle deux exclut un en-tête défini sur une page HTTP non chiffrée.
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 contient le chemin et la chaîne de requête. Un lecteur sur https://example.com/guides/tor se voit donc proposer le même chemin sur l’onion. Si vous l’omettez, chaque visiteur arrive sur la page d’accueil de l’onion au lieu de retrouver la page qu’il consultait.
always est important en raison d’une limite documentée de nginx. add_header ajoute le champ uniquement lorsque le code de réponse est 200, 201, 204, 206, 301, 302, 303, 304, 307 ou 308. Votre page 404 constitue un véritable point d’entrée depuis les résultats de recherche. Sans always, elle ne contient aucun en-tête.
Le deuxième piège de nginx concerne l’héritage, qui échoue silencieusement. Les directives add_header sont héritées du niveau de configuration précédent uniquement s’il n’existe aucune directive add_header au niveau actuel. Ainsi, un bloc location /assets/ { add_header Cache-Control ...; } ignore le Onion-Location défini au niveau server pour toutes les URL qu’il contient. Si vous définissez des en-têtes propres à chaque location, répétez la ligne Onion-Location dans chacun de ces blocs. Comment nginx sélectionne un bloc server et un bloc location mérite d’être lu si ce comportement vous est nouveau.
Rechargez la configuration et vérifiez une page normale ainsi qu’une page inexistante :
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-locationLes deux commandes doivent afficher une ligne onion-location:. La seconde confirme que always fonctionne. Si la seconde commande n’affiche rien, le flag est absent ou un bloc location masque la directive.
La balise meta HTML lorsque vous ne pouvez pas définir d’en-têtes
Les hébergeurs statiques et certains tableaux de bord CDN ne permettent pas d’ajouter un en-tête de réponse arbitraire. La même valeur fonctionne comme élément meta dans l’en-tête du document, car le navigateur la lit dans les mêmes données d’en-tête du document, qu’elle soit reçue via HTTP ou sous la forme d’une balise http-equiv.
<meta http-equiv="onion-location" content="http://<your-onion-address>.onion" />Les trois conditions restent applicables. La page qui contient la balise doit être en HTTPS et ne doit pas être une adresse onion. La différence est que la balise contient une adresse fixe sans chemin, car aucune variable côté serveur ne peut être développée. Chaque page qui la contient propose la page d’accueil onion. C’est le coût de cette solution de repli : privilégiez donc l’en-tête lorsque vous contrôlez le serveur.
Servir l’onion avec son propre vhost nginx
Le site clearnet et l’onion ne doivent pas partager le même bloc server. Tor Browser envoie Host: <your-onion-address>.onion. Si aucun bloc server ne revendique ce nom, nginx utilise le serveur par défaut, qui correspond à votre vhost clearnet, et toutes les URL générées par ce vhost contiennent votre domaine.
Pointez le hidden service vers un port auquel seule l’interface loopback répond :
HiddenServiceDir /var/lib/tor/onion_site/
HiddenServicePort 80 127.0.0.1:8080Attribuez ensuite ce port à son propre vhost :
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 empêche ce vhost d’être accessible via votre IP publique. Une personne qui scanne l’adresse du VPS ne peut donc pas le récupérer et le comparer octet par octet avec la copie clearnet. absolute_redirect off demande à nginx d’émettre des valeurs Location relatives. Ainsi, la redirection avec slash final d’un répertoire renvoie Location: /guides/ et non une URL complète. nginx construit déjà les redirections absolues à partir de l’en-tête Host plutôt qu’à partir de server_name, car server_name_in_redirect vaut par défaut off. Toutefois, une redirection relative supprime entièrement cette question.
Pourquoi la page onion redirige-t-elle encore les visiteurs vers le site clearnet ?
nginx est rarement à l’origine de la fuite. C’est généralement votre application. Tout ce qui construit une URL absolue à partir de l’adresse configurée du site utilise votre domaine, quel que soit le virtual host qui a traité la requête.
- Une balise de lien
rel="canonical"pointant vershttps://example.com/.... C’est le cas le plus fréquent. Elle révèle l’URL exacte de la page clearnet à toute personne qui consulte le code source. - Les redirections générées par le framework plutôt que par nginx, comme
SECURE_SSL_REDIRECTdans Django ou les optionshomeetsiteurlde WordPress. og:urlet les autres balises meta utilisées par les cartes sociales.- Les entrées Sitemap et RSS, qui sont absolues par définition.
- Les pages d’erreur de l’application, qui contiennent généralement un lien « retour à la page d’accueil » construit à partir du même paramètre.
La correction dépend de votre stack. Il n’existe pas de solution générique. La vérification, elle, est générique. Récupérez la page onion via Tor et recherchez votre domaine dans la réponse.
curl -s --socks5-hostname 127.0.0.1:9050 http://<your-onion-address>.onion/ \
| grep -i 'example\.com'--socks5-hostname transmet le nom au port SOCKS de Tor pour sa résolution. Cette étape est nécessaire, car rien sur votre machine ne peut résoudre localement un nom .onion. Le port 9050 est le port par défaut d’un daemon Tor installé depuis un paquet. Un résultat vide indique que le contrôle est réussi. Toute occurrence indique qu’une page transmet votre domaine clearnet à chaque visiteur onion. Exécutez le contrôle sur la page d’accueil, puis sur une URL qui produit une erreur 404.
Vérifiez séparément la chaîne de redirections, car le corps d’une redirection est généralement vide :
curl -sI --socks5-hostname 127.0.0.1:9050 http://<your-onion-address>.onion/guides \
| grep -i '^location'Une valeur Location contenant example.com indique qu’une redirection renvoie votre visiteur onion vers le clearnet, via un nœud de sortie, alors qu’il pensait rester à l’intérieur de Tor.
Ne présentez pas le certificat clearnet sur l’adresse onion
Une adresse onion v3 est dérivée de la clé publique du service concerné. Tor authentifie et chiffre donc le circuit vers ce service précis avant l’envoi de toute requête HTTP. Le HTTP en clair à l’intérieur d’un service onion est la configuration normale. Il ne s’agit pas de la même chose que du HTTP en clair sur Internet.
Si vous construisez le vhost onion en copiant celui du clearnet, vous copiez aussi ssl_certificate. L’adresse onion présente alors un certificat dont les noms alternatifs du sujet contiennent example.com. Deux problèmes se posent. Le navigateur signale une discordance de nom, car l’URL est l’adresse onion et le certificat ne la couvre pas. De plus, chaque visiteur qui passe outre reçoit une déclaration signée indiquant que ces deux sites sont hébergés sur la même machine. Conservez le vhost onion dans son propre fichier avec son propre server_name. Il restera ainsi distinct du plugin nginx de Certbot, qui modifie le server block correspondant au domaine pour lequel vous demandez un certificat.
Quel paquet tor utiliser et comment protéger la clé du service
Le paquet tor présent dans l’archive Ubuntu convient et ne nécessite aucune configuration supplémentaire. Il est en retard sur la série stable actuelle. Pour un service que vous prévoyez de laisser fonctionner, utilisez donc le dépôt Debian du projet Tor et laissez apt le mettre à niveau avec le reste du système. En août 2026, les étapes documentées sont les suivantes :
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/nullÉcrivez /etc/apt/sources.list.d/tor.sources en remplaçant la suite par le nom de code de votre version, obtenu avec 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-keyringLe paquet deb.torproject.org-keyring maintient la clé de signature à jour. Le dépôt continuera ainsi à être vérifié dans un an. Choisissez une seule source et utilisez-la exclusivement. Le paquet de l’archive et celui du dépôt ont des versions différentes. Si les deux sources sont activées, apt peut basculer de l’une à l’autre lors des mises à niveau.
Le répertoire HiddenServiceDir contient l’identité de votre service. Le fichier hs_ed25519_secret_key présent dans ce répertoire est votre adresse onion, car cette adresse correspond à la partie publique de cette paire de clés. Si vous perdez ce fichier, l’adresse est définitivement perdue : aucune autorité ne peut la réattribuer. Si vous copiez ce fichier dans un emplacement mal protégé, toute personne qui possède la copie peut exécuter votre service onion.
tor refuse d’utiliser un répertoire lisible par d’autres utilisateurs. Vérifiez d’abord les permissions et le propriétaire :
sudo ls -ld /var/lib/tor/onion_site
sudo -u debian-tor cat /var/lib/tor/onion_site/hostnameLa sortie doit indiquer drwx------, avec le propriétaire et le groupe debian-tor sur Debian et Ubuntu. Si les permissions sont plus larges, tor écrit une ligne telle que Permissions on directory /var/lib/tor/onion_site/ are too permissive. dans les journaux et le service ne démarre pas. Corrigez la situation avec sudo chown -R debian-tor:debian-tor /var/lib/tor/onion_site, puis sudo chmod 700 /var/lib/tor/onion_site, redémarrez avec sudo systemctl restart tor et vérifiez le résultat avec sudo journalctl -u tor@default -n 30.
Sauvegardez ce répertoire comme vous sauvegardez une clé privée : hors du serveur et sous forme chiffrée. Ne l’intégrez jamais au dépôt qui contient votre site. Si le même serveur doit également fournir un accès administratif via Tor, accéder à SSH via un service onion sépare mieux les usages que l’exposition d’un chemin d’administration sur le site public.
Les outils d’analytics et les ressources tierces divulguent plus d’informations que l’en-tête
C’est la partie la plus importante, et elle n’a rien à voir avec Onion-Location. Chaque ressource tierce référencée par votre page déclenche une requête du navigateur du visiteur, qui sort du réseau onion et repasse sur le clearnet par un nœud de sortie. Une police provenant d’un CDN public, un script d’analytics hébergé ailleurs, un lecteur vidéo intégré ou un module de commentaires : chacun de ces éléments indique au tiers concerné que quelqu’un charge votre page au cours d’une session que le lecteur a délibérément fait transiter par Tor.
Cela a deux conséquences. Le tiers apprend qu’une personne a consulté la page. Et comme votre copie clearnet charge les mêmes ressources auprès des mêmes fournisseurs, toute personne ayant une vue sur l’un ou l’autre site peut associer les deux propriétés sans difficulté.
Servez toutes les ressources depuis la même origine. Hébergez vous-même vos polices. Supprimez la balise d’analytics hébergée ailleurs ou déplacez-la sur votre propre serveur, où l’analytics auto-hébergé sur un VPS maintient la requête à l’intérieur du réseau onion. Attendez-vous à ce que les paramètres par défaut de Tor Browser bloquent ou limitent fortement une grande partie des données qu’un outil d’analytics tente de collecter. C’est le résultat attendu. Si une page ne peut pas fonctionner sans script tiers, ne publiez pas cette page sur le réseau onion.
Listez ce qu’une page charge réellement :
curl -s --socks5-hostname 127.0.0.1:9050 http://<your-onion-address>.onion/ \
| grep -oE '(src|href)="https?://[^"]+"' | sort -uChaque ligne affichée est une URL absolue que votre page demande au navigateur de récupérer. Toute URL qui n’est pas votre propre adresse onion correspond à une requête sortante vers le clearnet que vous demandez à vos lecteurs d’effectuer pour vous.
Le modèle de menace, en termes simples
Onion-Location permet de trouver facilement un service onion, et c’est tout. Il ne vous anonymise pas en tant qu’opérateur, car votre domaine clearnet conserve les informations du registrar, les enregistrements DNS, un certificat publié dans les journaux Certificate Transparency et un compte VPS associé à vos informations de facturation. Il n’anonymise pas non plus le service onion, car vous venez de publier depuis ce domaine clearnet une déclaration publique durable indiquant que les deux adresses correspondent au même site. L’avantage revient au lecteur : une personne qui arrive par Tor peut rester dans Tor, sans nœud de sortie sur le chemin et sans requête DNS pour votre domaine. Si votre objectif est de proposer un service onion auquel personne ne peut vous relier, ne publiez pas cet en-tête et n’exécutez pas les deux copies sur la même machine.
Deux questions liées se posent ici, et chacune a sa propre réponse. La différence entre Tor et un VPN détermine ce que vous utilisez pour votre propre trafic, ce qui est une décision distincte de ce que vous publiez. Et si les lecteurs d’un réseau soumis à la censure ne peuvent pas du tout atteindre le site clearnet, ils ne voient jamais l’en-tête. C’est dans ce cas que les bridges et les transports enfichables comptent davantage que tout le reste de cette page.
Vérifiez toute la configuration une fois
Exécutez ces commandes dans l’ordre. Chacune produit un résultat que vous pouvez vérifier.
curl -sI https://example.com/ | grep -i onion-locationaffiche l’en-tête.- La même commande exécutée sur une URL qui renvoie 404 l’affiche également.
curl -s --socks5-hostname 127.0.0.1:9050 http://<your-onion-address>.onion/renvoie votre page.- Une recherche de votre domaine clearnet dans cette sortie ne renvoie aucun résultat.
- Dans Tor Browser, sur
https://example.com, la pastille.onion availables’affiche.
Si les étapes 1 à 4 réussissent, mais pas l’étape 5, la cause se trouve presque toujours à l’endroit où l’en-tête est servi, et non dans l’en-tête lui-même. Vérifiez que le navigateur a bien chargé la page HTTPS et non une redirection mise en cache, puis exécutez curl -sI sur l’URL exacte que vous avez ouverte, car un bloc location appliqué à ce chemin précis peut ignorer la directive définie au niveau du serveur.
FAQ
Pourquoi Tor Browser n’affiche-t-il pas le badge « .onion disponible » ?
Vérifiez d’abord les trois conditions documentées. La valeur doit être une URL complète avec un schéma http: ou https: et un hôte .onion. Une adresse seule, sans schéma, échoue donc sans afficher d’erreur. La page doit être servie en HTTPS. Un en-tête défini dans votre bloc de redirection du port 80 n’est donc jamais lu. Enfin, la page ne doit pas être elle-même un onion. Vérifiez ensuite nginx : tout add_header dans le bloc location correspondant supprime tous les add_header définis au niveau du serveur. Sans l’option always, l’en-tête est absent des réponses 404 et 500. Exécutez curl -sI sur l’URL exacte chargée dans le navigateur et vérifiez que l’en-tête est bien transmis sur le réseau.
Ai-je besoin d’un certificat TLS pour mon site onion ?
Non. Une adresse onion v3 est dérivée de la clé publique du service. Le circuit est donc authentifié auprès de ce service précis et chiffré de bout en bout avant l’envoi de toute requête HTTP. HTTP en clair dans un service onion est la configuration normale. Vous devez en revanche éviter de présenter votre certificat clearnet sur l’onion. Sa liste de noms alternatifs de sujet contient votre domaine. Le navigateur affiche alors un avertissement de non-correspondance du nom, et chaque visiteur comprend que les deux sites fonctionnent sur la même machine.
La publication de Onion-Location rend-elle mon site anonyme ?
Non. Cet en-tête indique publiquement, depuis votre domaine clearnet, qu’une adresse onion donnée vous appartient. N’importe qui peut le récupérer. Le bénéfice concerne le lecteur, qui peut basculer vers l’onion et retirer de son parcours le nœud de sortie ainsi que la résolution DNS. En tant qu’opérateur, vous ne gagnez aucun anonymat et vous liez définitivement les deux adresses. Un service onion qui ne doit pas pouvoir être relié à vous doit être publié ailleurs, sur du matériel qui ne partage rien avec le site clearnet.
Puis-je utiliser la balise meta à la place de l’en-tête HTTP ?
Oui, lorsque vous ne pouvez pas définir les en-têtes de réponse, ce qui est généralement le cas sur un hébergement statique. Placez <meta http-equiv="onion-location" content="http://youraddress.onion" /> dans l’en-tête du document. Les trois mêmes conditions s’appliquent : la page doit être en HTTPS et ne doit pas être un onion. La seule différence réelle est que la balise contient une adresse fixe sans chemin, tandis que l’en-tête nginx peut ajouter $request_uri et proposer au visiteur la même page sur l’onion plutôt que la page d’accueil.