Héberger un site .onion sur votre VPS avec Tor
Créez un service onion v3 sur Ubuntu avec Tor et nginx sur loopback. Évitez les fuites qui pourraient relier l’adresse .onion à votre IP publique.
Ce que vous allez mettre en place
Un site onion est un serveur web normal qui répond uniquement sur le réseau Tor. Installez tor, ajoutez deux lignes à /etc/tor/torrc, relevez l’adresse que tor écrit pour vous, puis faites écouter nginx sur 127.0.0.1 afin qu’aucun service ne réponde sur l’IP publique. L’installation prend dix minutes. Le reste de ce guide porte sur les fuites, car un site onion échoue généralement lorsque sa propre configuration renvoie directement vers l’opérateur.
Tor signifie à l’origine « the onion router », et un service onion est un service accessible uniquement par son intermédiaire. Une adresse de version 3 comporte 56 caractères suivis de .onion. Ces caractères correspondent à la clé publique ed25519 du service, à une somme de contrôle et à un octet de version, le tout encodé en base32. Les adresses de version 2, qui comportaient 16 caractères, ont été supprimées du réseau en 2021. Tout ce que vous générez aujourd’hui est donc en v3. L’adresse est la clé, ce qui a deux conséquences. La connexion est chiffrée et authentifiée de bout en bout, sans intervention d’une autorité de certification. Si vous perdez le fichier de clé, vous perdez définitivement l’adresse.
Votre serveur n’accepte jamais de connexion entrante. Tor sélectionne quelques relais comme points d’introduction, téléverse un descripteur signé vers les serveurs d’annuaire, puis met chaque visiteur en relation avec votre serveur via un relais de rendez-vous choisi par le visiteur. Toutes ces connexions sont sortantes depuis votre serveur. Vous n’avez aucun port à ouvrir et aucun enregistrement DNS à publier. Si vous voulez que le même VPS fournisse un service au réseau, il s’agit d’une tâche différente, avec une architecture opposée, car un bridge obfs4 accepte les connexions entrantes de clients soumis à la censure et nécessite un port accessible.
Installer Tor depuis le dépôt du projet Tor
Ubuntu fournit un paquet tor dans le dépôt universe, mais sa version reste proche de celle qui était actuelle au moment du gel de la version. Le dépôt du projet Tor suit la version stable actuelle. C’est ce qu’il vous faut pour le logiciel qui détermine si votre adresse reste la vôtre. La présence d’un paquet dans une distribution ne dit rien sur la poursuite de son développement. C’est un point à vérifier pour tout service que vous auto-hébergez, car Searx n’a reçu aucun commit de code depuis 2023, tandis que SearXNG poursuit le développement de ce projet.
sudo apt update
sudo apt install -y apt-transport-https gnupg wget
KEYURL=https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc
wget -qO- "$KEYURL" | gpg --dearmor | sudo tee /usr/share/keyrings/deb.torproject.org-keyring.gpg >/dev/nullL’entrée du dépôt utilise le format deb822, et Suites doit être le nom de code de votre version d’Ubuntu. Lisez-le dans /etc/os-release au lieu de le saisir, car un nom de code incorrect produit un dépôt qui se résout correctement, mais qui ne contient aucun paquet pour votre version.
. /etc/os-release
sudo tee /etc/apt/sources.list.d/tor.sources >/dev/null <<EOF
Types: deb deb-src
URIs: https://deb.torproject.org/torproject.org/
Suites: $VERSION_CODENAME
Components: main
Signed-By: /usr/share/keyrings/deb.torproject.org-keyring.gpg
EOF
sudo apt update
sudo apt install -y tor deb.torproject.org-keyringLe paquet deb.torproject.org-keyring maintient la clé de signature à jour. Une rotation de clé ne bloquera donc pas apt update dans un an. Vérifiez que tor a démarré et a atteint le réseau :
tor --version
sudo journalctl -u tor@default -n 20Le journal doit se terminer par Bootstrapped 100% (done): Done. Un processus tor bloqué à Bootstrapped 10% ne dispose d’aucune voie sortante. Vérifiez le pare-feu réseau de votre fournisseur et vos propres règles de trafic sortant : sudo ufw status verbose doit afficher allow (outgoing) comme route par défaut.
Deux noms sont importants à partir de maintenant. Le paquet exécute tor avec l’utilisateur debian-tor, et l’unité en cours d’exécution est tor@default.service, car tor.service sur Debian et Ubuntu est un wrapper autour de l’instance. Demandez l’état et les journaux avec le nom de l’instance afin d’obtenir systématiquement le processus réel.
Configurer le service onion dans torrc
Ajoutez deux lignes à /etc/tor/torrc :
HiddenServiceDir /var/lib/tor/onion_site/
HiddenServicePort 80 127.0.0.1:8080HiddenServiceDir est le répertoire dans lequel Tor conserve les clés et l’adresse de ce service. Ne le créez pas vous-même. Tor le crée au démarrage avec le propriétaire et le mode nécessaires. Un répertoire créé par root provoque la première erreur de la liste ci-dessous.
HiddenServicePort comporte deux parties. Les confondre est l’erreur la plus fréquente au début. Le premier nombre est le port auquel un visiteur se connecte à l’intérieur du tunnel. 80 est donc le choix attendu et il n’y a aucune raison de le modifier. La seconde partie est l’adresse locale vers laquelle Tor transmet ce trafic. Une valeur HiddenServicePort 80 transmet vers 127.0.0.1:80. En indiquant explicitement l’adresse et en utilisant un port élevé, vous évitez que le vhost onion entre en conflit avec un service qui écoute déjà sur le port 80.
sudo systemctl restart tor@default
sudo ls -l /var/lib/tor/onion_site/Le répertoire doit contenir hostname, hs_ed25519_public_key, hs_ed25519_secret_key et un répertoire authorized_clients vide.
Lire votre adresse .onion
sudo cat /var/lib/tor/onion_site/hostnameUne ligne s’affiche : 56 caractères base32 et .onion. Cette chaîne constitue l’identité complète du site. Personne ne l’attribue, ne peut la transférer ni vous la retirer tant que vous détenez le fichier de clé. Copiez-la maintenant, car toutes les configurations ci-dessous en ont besoin. La suite de ce guide la note <your-address>.onion.
Servir le site depuis nginx lié à 127.0.0.1
sudo apt install -y nginx
sudo install -d -m 755 /srv/onionÉcrivez /etc/nginx/sites-available/onion :
server {
listen 127.0.0.1:8080;
server_name <your-address>.onion;
root /srv/onion;
index index.html;
server_tokens off;
etag off;
access_log off;
error_log /var/log/nginx/onion.error.log error;
}echo '<h1>hello from the onion</h1>' | sudo tee /srv/onion/index.html
sudo ln -s /etc/nginx/sites-available/onion /etc/nginx/sites-enabled/onion
sudo nginx -t
sudo systemctl reload nginxVérifiez maintenant deux éléments depuis le serveur. Le premier est que nginx répond pour le nom onion. Il s’agit de l’en-tête Host exact que tor enverra :
curl -s -H 'Host: <your-address>.onion' http://127.0.0.1:8080/Le second est qu’il répond à cette adresse, et nulle part ailleurs :
sudo ss -tlnp | grep 8080La colonne des adresses doit afficher 127.0.0.1:8080. Si elle affiche 0.0.0.0:8080 ou *:8080, votre site onion est également accessible depuis l’Internet public. C’est le premier élément de la liste des fuites. Une ligne listen 8080; sans adresse lie le service à toutes les interfaces. C’est le comportement par défaut.
Ouvrez l’adresse dans Tor Browser. Le premier chargement prend quelques secondes, le temps que le client récupère votre descripteur et construise un circuit de rendezvous.
La documentation officielle de Tor recommande plutôt un socket Unix qu’un port loopback : HiddenServicePort 80 unix:/var/run/tor/onion_site.sock, nginx écoutant sur ce chemin. Un socket ne peut jamais être atteint depuis un autre hôte, même si la machine reçoit plus tard une deuxième interface. En contrepartie, il faut gérer les permissions de fichiers : nginx crée le socket et tor s’y connecte sous l’utilisateur debian-tor. Les deux utilisateurs doivent donc avoir accès au répertoire. Le loopback avec une sortie ss vérifiée est plus simple à configurer correctement. C’est l’approche retenue dans la suite de ce guide.
Avec le site lié au loopback, la machine n’a besoin d’aucune règle entrante pour ce service. Gardez 22 ouvert pour vous et refusez le reste (les valeurs par défaut de ufw à définir sur un VPS). N’oubliez pas qu’un firewall ne neutralise pas un service lié à 0.0.0.0. Il filtre uniquement les paquets qui atteignent le firewall. Les conteneurs rendent ce point encore plus important, car la publication d’un port Docker écrit des règles iptables avant celles de ufw. Ainsi, -p 8080:80 place votre backend onion sur l’adresse IP publique, alors que ufw indique toujours que le port est refusé. Publiez les ports des conteneurs avec -p 127.0.0.1:8080:80.
Les fuites qui désanonymisent un site onion
Tor masque l’emplacement du serveur. Tor ne masque pas ce que le serveur publie. Chaque élément ci-dessous est une information publiée par votre propre stack. Lire chaque outil de confidentialité en fonction de sa limite réelle, et non de sa réputation, relève de la même démarche que ce que masque un SearXNG auto-hébergé : votre adresse IP aux moteurs de recherche, et rien de plus.
Le même site répond sur votre IP publique
C’est le cas qui surprend le plus souvent. Les scanners indexent en permanence la réponse HTTP de chaque adresse routable, et ces résultats sont publics et consultables. Servez la même page sur votre IP publique et sur votre adresse onion : les relier devient une simple requête, avec le même titre, le même hash de favicon, le même ETag et le même ordre d’en-têtes. La ligne listen 127.0.0.1:8080; ci-dessus corrige le problème. Vérifiez-la depuis une autre machine, pas depuis le serveur :
curl -sv --max-time 5 http://<your-public-ip>:8080/Connection refused ou un délai d’expiration est le résultat attendu. La présence de HTML signifie que le site est public. Si la machine héberge aussi un site clearnet, attribuez à ce vhost sa propre racine et conservez un bloc default_server explicite sur l’écouteur public, afin qu’un en-tête Host non reconnu ne puisse jamais tomber sur le vhost onion.
Bannières de version
curl -sI http://127.0.0.1:8080/ | grep -i '^server'Un nginx installé par défaut répond avec Server: nginx/1.24.0. Cette chaîne de version, associée à l’ordre exact des autres en-têtes, constitue une empreinte qui permet de relier votre site onion à votre hôte clearnet. server_tokens off; la réduit à Server: nginx. Cela ne supprime pas l’en-tête. nginx ne possède aucune directive intégrée pour le supprimer. Le module headers-more est donc la solution habituelle si vous voulez le faire disparaître. PHP ajoute X-Powered-By jusqu’à ce que vous définissiez expose_php = Off. etag off; doit figurer dans la même liste, car nginx construit l’ETag à partir de la date de modification et de la taille du fichier. Les mêmes fichiers copiés sur deux serveurs produisent donc le même ETag sur les deux.
URL absolues pointant vers votre domaine clearnet
Une balise rel="canonical", un og:url Open Graph, un flux RSS, un sitemap, un e-mail de réinitialisation de mot de passe ou une URL de logo codée en dur. Un seul de ces éléments suffit à nommer le site clearnet dans une page servie sur onion. Utilisez des chemins relatifs à la racine, comme /static/logo.svg, et faites lire à l’application son URL de base depuis l’hôte de la requête plutôt que depuis une constante. Les redirections posent le même problème ailleurs : return 301 https://example.com$request_uri; dans un bloc fourre-tout redirige le visiteur onion vers votre domaine réel, et l’en-tête Location lui fournit directement la réponse.
Un certificat TLS partagé avec le site clearnet
Une adresse onion s’authentifie elle-même, puisque l’adresse est la clé publique. Ainsi, http:// sur une connexion onion est déjà chiffré de bout en bout, et Tor Browser le traite comme un contexte sécurisé. Installer votre certificat existant sur le vhost onion publie le lien entre les deux, car tout certificat approuvé publiquement est enregistré dans les journaux Certificate Transparency. Ces journaux sont publics, permanents et consultables par nom. Conservez les certificats Let's Encrypt sur le vhost clearnet et laissez le vhost onion en HTTP simple.
Polices et outils d’analyse tiers
Une police provenant d’un CDN (content delivery network) ou un script d’analyse. Le navigateur du visiteur récupère directement chacun de ces éléments. Le tiers apprend donc que quelqu’un a chargé votre page et, généralement, quelle page. Les niveaux de sécurité plus stricts de Tor Browser bloquent en outre la requête, ce qui produit une mise en page incorrecte. Hébergez vous-même tous les éléments nécessaires à la page.
Incohérence de l’en-tête Host
Si server_name ne correspond pas à l’en-tête Host envoyé par Tor, nginx utilise le serveur par défaut pour cette adresse d’écoute. Sur une machine avec un seul vhost, cela ne se voit pas, car l’unique bloc server est aussi le serveur par défaut. Si vous ajoutez ensuite un vhost clearnet, les requêtes onion peuvent commencer à y arriver, avec ses balises canoniques et ses redirections. Relancez le contrôle curl -H 'Host: ...' après chaque modification de nginx et recherchez votre domaine réel dans le résultat :
curl -s -H 'Host: <your-address>.onion' http://127.0.0.1:8080/ | grep -o 'https\?://[^"]*' | sort -uSavoir quel processus possède quel socket couvre une grande partie de ce travail (comment fonctionnent les ports et les sockets en écoute sous Linux).
Ce qui reste dans les journaux
Chaque requête arrive depuis 127.0.0.1. nginx ne dispose donc d’aucune adresse de visiteur à enregistrer, et access_log off; ne vous coûte rien. L’application située au-dessus est un autre sujet : une commande, une adresse e-mail ou les métadonnées d’un fichier envoyé sont sous votre responsabilité. Vos propres habitudes comptent également. Administrer la machine avec une connexion non renforcée ne bénéficie d’aucune protection de Tor. Considérez donc le renforcement de SSH sur le même VPS comme une partie intégrante de cette configuration.
Sauvegardez la clé privée, car elle constitue l’adresse
/var/lib/tor/onion_site/hs_ed25519_secret_key est le service. Il n’y a ni bureau d’enregistrement ni procédure de récupération. Si vous la perdez, l’adresse disparaît. Copiez-la, et toute personne qui détient la copie peut diffuser son propre contenu à votre adresse, sans aucun moyen pour vous de révoquer quoi que ce soit.
sudo systemctl stop tor@default
sudo tar -C /var/lib/tor -czf onion-keys.tgz onion_site
sudo chmod 600 onion-keys.tgz
sudo systemctl start tor@defaultChiffrez cette archive (gpg -c onion-keys.tgz) et transférez-la hors du serveur. La restauration sur un nouveau VPS consiste à utiliser l’archive et à respecter les attentes de tor concernant la propriété :
sudo systemctl stop tor@default
sudo tar -C /var/lib/tor -xzf onion-keys.tgz
sudo chown -R debian-tor:debian-tor /var/lib/tor/onion_site
sudo chmod 700 /var/lib/tor/onion_site
sudo systemctl start tor@default
sudo cat /var/lib/tor/onion_site/hostnameLa même adresse réapparaît sur le nouveau matériel une ou deux minutes après que tor a republie le descripteur. C’est toute la migration : aucun changement DNS et aucun renouvellement de certificat.
Onion-Location, lorsque le site est également accessible sur le clearnet
Si l’adresse onion est un accès pratique et non un secret, publiez-la depuis le vhost du clearnet :
add_header Onion-Location http://<your-address>.onion$request_uri;Tor Browser affiche alors un bouton .onion available dans la barre d’adresse et propose de basculer vers cette adresse. L’en-tête n’est pris en compte que lorsque la page du clearnet est servie en HTTPS et que la valeur est une URL onion valide.
Une règle nginx peut poser problème ici. Les directives add_header ne sont héritées par un bloc location que si celui-ci ne déclare aucune directive de ce type. Ainsi, un location qui contient son propre add_header ignore silencieusement Onion-Location. Répétez la directive à cet endroit ou regroupez tous les en-têtes de réponse au même endroit. La publication volontaire de cet en-tête associe les deux sites. C’est approprié pour un miroir, mais pas pour un site qui doit rester sans lien avec l’autre.
Adresses personnalisées
mkp224o génère des paires de clés jusqu’à ce que l’une d’elles produise une adresse commençant par le préfixe demandé. Il s’agit d’une recherche par force brute. Il n’y a donc rien à configurer en dehors du préfixe et du délai que vous êtes prêt à attendre.
sudo apt install -y git gcc libc6-dev libsodium-dev make autoconf
git clone https://github.com/cathugger/mkp224o
cd mkp224o
./autogen.sh
./configure --enable-amd64-51-30k
make
./mkp224o -d onionkeys blogChaque résultat est enregistré dans onionkeys/<address>.onion/, qui contient hostname et hs_ed25519_secret_key. Installez-en un en arrêtant tor, en copiant ce répertoire dans votre HiddenServiceDir, puis en appliquant les mêmes chown et chmod 700 que pour la restauration ci-dessus.
La longueur du préfixe représente l’intégralité du coût. L’adresse est encodée en base32. Chaque caractère supplémentaire demandé multiplie donc par 32 le nombre de clés attendu. Un préfixe court peut être généré sur un ordinateur portable. Un préfixe long ne sera généré sur aucun matériel que vous possédez. Un préfixe personnalisé incite aussi les lecteurs à reconnaître les premiers caractères plutôt que l’adresse complète. C’est précisément l’habitude sur laquelle reposent les copies de sites onion utilisées pour le phishing.
Modes de panne, avec les chaînes que vous verrez
Aucun fichier hostname après le redémarrage. Tor n’a pas démarré ou a refusé le répertoire. sudo journalctl -u tor@default -n 50 l’indique :
/var/lib/tor/onion_site/ is not owned by this user (debian-tor, 108) but by root (0). Perhaps you are running Tor as the wrong user?C’est à cela que ressemble un répertoire créé manuellement. Corrigez le propriétaire et les permissions, ou supprimez le répertoire et laissez tor le créer.
Tor Browser affiche Onionsite Not Found (0xF0). Le client n’a pas pu récupérer de descripteur. Pour le réseau, aucune adresse n’est donc publiée à cette adresse. Vérifiez que tor fonctionne et a terminé son bootstrap, comparez l’adresse saisie avec sudo cat /var/lib/tor/onion_site/hostname caractère par caractère, puis vérifiez l’horloge. Tor a besoin d’une heure exacte pour publier et valider les descripteurs, et timedatectl doit afficher System clock synchronized: yes.
L’adresse est résolue, mais la page ne se charge jamais. Tor a terminé le rendezvous, puis a échoué sur le dernier saut, entre tor et nginx. Ce saut est local, donc le journal de tor reste silencieux. Exécutez curl -sI http://127.0.0.1:8080/ sur le serveur. Connection refused signifie que nginx est arrêté ou écoute sur une autre adresse que celle indiquée par HiddenServicePort.
La page se charge et chaque lien renvoie vers votre vrai domaine. Les templates contiennent des URL absolues. Exécutez le contrôle grep -o 'https\?://[^"]*' ci-dessus et corrigez ce qu’il affiche avant de communiquer l’adresse.
Cela fonctionne, puis s’arrête après un redémarrage. Redémarrez volontairement la machine une fois avant de vous fier au site, puis exécutez sudo systemctl status tor@default et sudo systemctl status nginx. Un service démarré manuellement ressemble à un service activé jusqu’au redémarrage de la machine.
FAQ
Dois-je ouvrir un port dans mon pare-feu pour un service onion Tor ?
Non. Le daemon tor établit uniquement des connexions sortantes vers les serveurs d’annuaire, ses points d’introduction et chaque relais de rendez-vous. Aucune règle entrante n’est donc nécessaire, et le serveur web écoute lui-même sur 127.0.0.1. Laissez ufw avec le refus par défaut du trafic entrant et autorisez SSH. Cette caractéristique permet également à un service onion de fonctionner depuis une machine derrière un NAT (traduction d’adresses réseau), sans aucune adresse IP publique.
Pourquoi ne puis-je pas accéder à mon adresse .onion dans Tor Browser ?
Partez du serveur et vérifiez chaque élément. sudo journalctl -u tor@default -n 50 doit afficher Bootstrapped 100% (done): Done. Ensuite, curl -sI http://127.0.0.1:8080/ exécuté sur le serveur doit renvoyer une ligne d’état. Comparez enfin l’adresse saisie avec le fichier hostname, car un seul caractère incorrect désigne simplement un autre service. Onionsite Not Found (0xF0) signifie qu’aucun descripteur n’a été trouvé pour cette adresse. Cela indique généralement que tor n’est pas démarré ou que l’horloge système est incorrecte.
Puis-je déplacer mon site onion vers un nouveau serveur tout en conservant la même adresse ?
Oui. L’adresse est dérivée de hs_ed25519_secret_key. Copiez donc l’intégralité de HiddenServiceDir sur le nouveau serveur, attribuez-le à debian-tor et appliquez le mode 700, puis démarrez tor. L’adresse redevient active lorsque le descripteur est de nouveau publié. Aucun enregistrement DNS n’est à modifier. Si vous perdez ce fichier, l’adresse ne peut pas être récupérée. Sauvegardez-le donc de manière chiffrée, hors du serveur, dès le jour de sa création.
Un site onion a-t-il besoin d’un certificat HTTPS ?
Non. L’adresse de 56 caractères est la clé publique du service. La connexion est donc déjà chiffrée et authentifiée de bout en bout, et Tor Browser considère http:// sur un nom .onion comme un contexte sécurisé. Réutiliser votre certificat clearnet sur le vhost onion est pire que ne rien faire, car les journaux Certificate Transparency sont publics et enregistrent définitivement les noms associés à un même certificat. La seule raison d’acheter un certificat pour un nom .onion est d’obtenir une garantie de marque auprès d’une CA qui en délivre. Ce lien est public par conception.