SSD Nodes Learn 🎉 VPS dès $4.99/mois
Guides Matt ConnorPar Matt Connor

Configurer un subnet router Tailscale sur un VPS

Exposez un réseau privé à votre tailnet depuis un VPS : approbation de route, IP forwarding persistant après reboot et flag --accept-routes requis sous Linux.

Ce que fait un subnet router Tailscale

Un subnet router Tailscale est une machine qui annonce toute une plage d’adresses IP privées à votre tailnet, afin que chaque appareil du tailnet puisse atteindre les adresses de cette plage, même si aucun appareil de cette plage n’exécute Tailscale. Votre tailnet est votre réseau Tailscale privé : l’ensemble des appareils connectés au même compte ou à la même organisation. L’exit node est la fonctionnalité avec laquelle on le confond souvent, mais son rôle est inverse. Il achemine tout le trafic d’un appareil via le VPS, qui devient alors la route de cet appareil vers Internet public.

Une phrase pour chacun. Un subnet router rend un réseau privé accessible depuis le tailnet. Un exit node modifie le point de sortie de votre trafic public. Si c’est cette deuxième fonction que vous recherchez, consultez plutôt comment exécuter un exit node Tailscale sur un VPS. Il s’agit de flags distincts. Un même VPS peut assurer les deux fonctions simultanément, mais elles répondent à des besoins différents et ne rencontrent pas les mêmes problèmes.

Quand un VPS doit servir de subnet router

Le cas courant concerne un réseau privé déjà fourni par votre hébergeur. Votre VPS possède une adresse publique et une seconde interface sur un segment privé. Les autres serveurs de ce segment n’ont aucune adresse publique : une base de données à 10.0.0.20 et une cible de sauvegarde à 10.0.0.30. Installez Tailscale sur un VPS, annoncez 10.0.0.0/24, puis votre ordinateur portable peut accéder directement à ces adresses privées. Rien d’autre ne change sur le segment et la base de données ne possède toujours aucune adresse publique.

L’autre cas concerne un réseau situé derrière le VPS. Il peut s’agir d’un LAN domestique ou professionnel derrière son propre routeur, ou d’un ensemble d’équipements qui ne peuvent pas exécuter Tailscale, comme un switch administrable ou un ancien NAS doté d’un firmware verrouillé. Une machine Linux de ce réseau devient le subnet router pour tous les autres équipements qui s’y trouvent.

Les deux cas ont un point commun. Le subnet router doit déjà pouvoir atteindre la plage qu’il annonce, avec sa propre table de routage et son propre firewall. Tailscale ne crée pas cette connexion. Il transporte le trafic jusqu’au routeur, puis le transmet au kernel, qui le forwarde.

Installer Tailscale et vérifier d’abord la route locale

curl -fsSL https://tailscale.com/install.sh | sh

Le script détecte la distribution, ajoute le dépôt de paquets Tailscale, installe la commande tailscale et le daemon tailscaled, puis active le service. Vérifiez le résultat avec systemctl is-active tailscaled, qui doit afficher active.

Avant toute autre chose, vérifiez que le VPS peut atteindre le réseau que vous prévoyez d’annoncer.

ip route show
ping -c3 10.0.0.20

ip route show doit lister la plage privée sur une interface réelle, par exemple 10.0.0.0/24 dev enp7s0 proto kernel scope link src 10.0.0.5. Si le ping échoue ici, directement vers le routeur, aucune option Tailscale ne pourra résoudre le problème. La cause se trouve dans la configuration réseau du VPS ou dans un firewall sur l’hôte cible. Corrigez-la d’abord, car tous les tests suivants en dépendent.

Activer le forwarding IP et le conserver après un redémarrage

Une machine Linux abandonne tout paquet qui ne lui est pas destiné si le forwarding n’est pas activé. Transmettre les paquets d’autres machines est la fonction même d’un routeur de sous-réseau. Cette étape est donc obligatoire.

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.conf

Vérifiez le réglage avec sysctl net.ipv4.ip_forward. La commande doit afficher net.ipv4.ip_forward = 1.

Cette étape est souvent configurée à moitié. sudo sysctl -w net.ipv4.ip_forward=1 fonctionne immédiatement, mais le réglage disparaît au prochain démarrage. Le routeur de sous-réseau peut donc fonctionner pendant plusieurs semaines, puis s’arrêter le matin suivant le redémarrage provoqué par une mise à niveau du kernel. Le problème est difficile à repérer, car rien ne semble cassé. tailscale status indique toujours que le nœud est en ligne, la console d’administration affiche toujours que la route est approuvée et les clients ont toujours la route installée. Les paquets arrivent sur le VPS, puis le kernel les abandonne sans rien écrire dans les logs. Écrire les valeurs dans /etc/sysctl.d/99-tailscale.conf permet de les restaurer après un redémarrage.

Si vous annoncez des routes alors que le forwarding est encore désactivé, tailscale up vous avertit immédiatement avec une ligne proche de Warning: IPv4 forwarding is disabled. Subnet routes and exit nodes may not work correctly.. Lisez la sortie de cette commande au lieu de la faire défiler sans la consulter.

Annoncer les routes

sudo tailscale up --advertise-routes=10.0.0.0/24

Sur un VPS déjà connecté à votre tailnet, modifiez plutôt le paramètre directement :

sudo tailscale set --advertise-routes=10.0.0.0/24

Utilisez tailscale set pour toutes les modifications ultérieures. Relancer tailscale up avec un seul flag réinitialise les flags que vous n’avez pas répétés. La CLI s’arrête alors avec une erreur indiquant que toute modification effectuée de cette manière doit mentionner tous les flags non définis par défaut. tailscale set modifie un seul paramètre et laisse les autres inchangés.

Plusieurs plages se placent dans une seule liste séparée par des virgules, sans espaces : --advertise-routes=10.0.0.0/24,192.168.50.0/24. Chaque entrée doit être une adresse réseau en notation CIDR (classless inter-domain routing, au format 10.0.0.0/24). Si vous indiquez par erreur votre propre adresse d’hôte, 10.0.0.5/24, la commande est rejetée, car les bits situés après le préfixe ne sont pas à zéro. L’erreur indique le préfixe que vous vouliez probablement utiliser. Pour arrêter l’annonce, définissez une liste vide avec sudo tailscale set --advertise-routes=.

Approuver la route dans la console d’administration

La publication d’une route est une demande, pas une modification immédiate. Tant qu’un administrateur ne l’a pas approuvée, aucun client ne reçoit la route et aucune adresse de la plage n’est accessible. C’est volontaire : une machine capable de s’ajouter à la table de routage de tout le monde pourrait intercepter le trafic de n’importe quelle plage.

Approuvez-la dans la page Machines de la console d’administration. Le VPS apparaît avec un badge de sous-réseau. Ouvrez sa ligne, repérez la section des sous-réseaux, modifiez les paramètres de route, cochez la route, puis enregistrez.

L’approbation s’applique à chaque préfixe. Publiez 10.0.0.0/24 aujourd’hui et 192.168.50.0/24 le mois prochain : le nouveau préfixe arrive alors sans approbation, tandis que l’ancien continue de fonctionner. Depuis le VPS, une route approuvée et une route ignorée sont identiques. Consultez donc la console avant de chercher une autre cause.

Vous pouvez supprimer cette étape manuelle avec un bloc autoApprovers dans le fichier de règles tailnet :

{
  "autoApprovers": {
    "routes": {
      "10.0.0.0/24": ["tag:subnet-router"]
    }
  }
}

Démarrez ensuite le nœud avec ce tag, sudo tailscale up --advertise-routes=10.0.0.0/24 --advertise-tags=tag:subnet-router. La route est alors approuvée dès sa publication. Le tag doit d’abord exister dans la section tagOwners du même fichier de règles. Cette configuration est utile si vous recréez le VPS avec un script : un nœud recréé est un nouveau nœud et ses routes redeviennent non approuvées.

Pourquoi les clients Linux ignorent la route sans --accept-routes

La route est maintenant annoncée et approuvée. Votre téléphone et votre Mac peuvent atteindre 10.0.0.20. Votre ordinateur portable Linux ne le peut pas, et rien dans la console d’administration n’indique de problème.

Accepter une route de sous-réseau signifie ajouter des entrées à la table de routage du client. Sous Android, iOS, macOS, tvOS et Windows, le client Tailscale s’en charge automatiquement. Sous Linux, ce n’est pas le cas, car une machine Linux est souvent un serveur ou un routeur dont la table de routage a été configurée volontairement. L’ajout silencieux d’une /24 apprise depuis le réseau pourrait interrompre le trafic que cette machine gère déjà. Sous Linux, vous devez donc activer cette fonction sur chaque client :

sudo tailscale set --accept-routes

Vérifiez ensuite où la route a été ajoutée :

ip route show table 52
ip route get 10.0.0.20

Sous Linux, Tailscale ne place pas les routes acceptées dans la table de routage principale. Il les place dans la table de routage 52 et installe des règles de routage par stratégie. Ces règles sont visibles avec ip rule show dans la plage de priorités 5210 à 5270 et envoient les paquets sans correspondance vers cette table. Ainsi, ip route show seul n’affichera jamais 10.0.0.0/24, et une personne qui vérifie uniquement cette commande conclura que --accept-routes n’a rien fait. ip route show table 52 est la commande qui affiche la situation réelle. Elle doit afficher la plage annoncée sur tailscale0.

Une exception mérite d’être connue. Si ce nœud Linux est lui-même un second subnet router pour son réseau local, --accept-routes lui fait envoyer le trafic destiné à son propre sous-réseau directement connecté via l’autre routeur, au lieu de l’envoyer par sa propre interface. Sur un routeur de secours dans une paire haute disponibilité, laissez --accept-routes désactivé et contentez-vous d’annoncer la route.

Mode de panne : deux routeurs annoncent des plages qui se chevauchent

Deux subnet routers ne doivent pas annoncer des plages identiques. Les plages qui se chevauchent avec des longueurs de préfixe différentes sont autorisées, et Tailscale utilise la correspondance la plus spécifique. Si le routeur A annonce 10.0.0.0/24 et le routeur B annonce 10.0.0.0/16, le trafic vers 10.0.0.20 passe par A.

Le comportement en cas de mise hors ligne de A est moins intuitif. Tailscale ne bascule pas vers la route moins spécifique. Le trafic vers 10.0.0.20 s’arrête, tandis que le trafic vers 10.1.0.20 continue de passer par B. Le symptôme donne l’impression que la moitié du réseau privé est indisponible. La cause est un nœud hors ligne qui détient le préfixe le plus spécifique. Pour assurer le failover, faites aussi annoncer les préfixes plus étroits par le routeur qui annonce la plage la plus large. Les deux routeurs couvrent ainsi les mêmes adresses.

L’autre chevauchement se situe plus près du client. Si vous êtes connecté à un réseau d’hôtel sur 192.168.1.0/24 alors que votre subnet router annonce 192.168.1.0/24, les deux routes entrent en concurrence pour les mêmes destinations. La route choisie dépend de la plate-forme. Sous Linux, installez une règle avant celle de Tailscale pour que les adresses locales utilisent la table principale :

sudo ip rule add to 192.168.1.0/24 priority 2500 lookup main

Cette règle n’est pas persistante et disparaît au prochain démarrage. La vraie solution consiste à choisir une plage privée que vous ne rencontrerez pas sur les réseaux auxquels vous vous connectez. 192.168.0.0/24 et 192.168.1.0/24 sont les valeurs par défaut de la plupart des routeurs domestiques. Choisissez donc une plage dans 10.0.0.0/8, après l’avoir définie délibérément. Le même conflit affecte un VPN WireGuard classique que vous configurez manuellement, pour la même raison : la route locale la plus spécifique est prioritaire, et le trafic n’entre donc jamais dans le tunnel.

Mode d’échec : le DNS résout le nom vers une adresse couverte par aucune route

Ce cas est difficile à diagnostiquer, car rien ne signale d’erreur. Le nom est résolu. La connexion expire.

Supposons que db.internal.example.com soit résolu vers 10.0.5.20 par votre nameserver privé et que vous ayez annoncé 10.0.0.0/24. La résolution réussit, car la résolution DNS (domain name system) et le routage IP sont deux étapes distinctes, et aucune ne vérifie l’autre. Le paquet destiné à 10.0.5.20 ne trouve aucune route correspondante sur le tailnet. Il sort donc par la passerelle par défaut du client et disparaît.

Deux commandes permettent de distinguer ces deux étapes :

nslookup db.internal.example.com
ip route get 10.0.5.20

Si la résolution renvoie une adresse, mais que ip route get ne répond pas avec dev tailscale0, le nom est correct et la route est manquante. Annoncez une plage qui couvre l’adresse, soit 10.0.0.0/16, soit un second préfixe explicite, puis approuvez le nouveau préfixe dans la console.

Le nameserver lui-même présente un piège similaire. Si vous définissez un nameserver global dans la console d’administration à une adresse privée telle que 10.0.0.53, cette adresse doit se trouver dans une route approuvée. Sinon, vos appareils ne peuvent pas atteindre le resolver. Si vous activez l’option qui remplace les serveurs DNS locaux tout en indiquant un resolver inaccessible, tous les appareils du tailnet perdent immédiatement la résolution des noms, y compris ceux qui fonctionnaient encore quelques secondes auparavant. Annoncez et approuvez d’abord la route vers le resolver, puis modifiez le paramètre DNS. Si le DNS dans un tunnel est la partie que vous devez constamment corriger, la façon dont le DNS tombe en panne dans un tunnel WireGuard décrit le même mécanisme, sans la couche de coordination supplémentaire.

NAT source et liaisons site à site

Par défaut, le subnet router réécrit l’adresse source de chaque paquet transféré avec sa propre adresse privée. C’est le SNAT (source network address translation). Il permet aux réponses de fonctionner sans modifier le réseau privé : la base de données à 10.0.0.20 répond au VPS, qu’elle sait déjà joindre. En contrepartie, la base de données voit toutes les connexions du tailnet comme provenant du VPS. Les règles de pare-feu par source et les journaux d’accès ne vous donnent donc aucune information utile.

Désactivez-le sous Linux lorsque vous voulez conserver l’adresse tailnet réelle du client :

sudo tailscale set --snat-subnet-routes=false

Les hôtes du réseau privé doivent alors disposer d’une route de retour vers 100.64.0.0/10, la plage que Tailscale attribue aux appareils, en passant par le subnet router. Sans cette route de retour, leurs réponses sont envoyées vers la passerelle par défaut et n’arrivent jamais à destination. Les connexions restent alors bloquées après le premier paquet. Ajoutez la route statique sur la passerelle du réseau privé, ou laissez le SNAT activé.

Une liaison site à site utilise deux subnet routers qui effectuent cette opération simultanément. Chacun annonce son propre réseau et accepte celui de l’autre :

sudo tailscale up --advertise-routes=10.0.0.0/24 --snat-subnet-routes=false --accept-routes

Exécutez la commande correspondante sur l’autre routeur avec sa propre plage. Les deux plages doivent être différentes. Si les transferts volumineux se bloquent alors que ssh et ping fonctionnent, la cause est le MSS (maximum segment size), c’est-à-dire la taille maximale des données transportées par un paquet TCP. La surcharge du tunnel rend les paquets transférés trop volumineux pour un équipement situé sur le chemin. Le clamping corrige ce problème :

sudo iptables -t mangle -A FORWARD -o tailscale0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

Enregistrez cette règle avec iptables-persistent, sinon elle disparaîtra au prochain démarrage.

Maintenance pour assurer le fonctionnement

Par défaut, les clés des nœuds expirent après 180 jours, depuis août 2026. Lorsque la clé d’un subnet router expire, le nœud est déconnecté et toute la plage annoncée devient inaccessible, sans qu’aucune modification de configuration ne permette de l’expliquer. Désactivez l’expiration des clés pour cette machine dans la page Machines de la console d’administration, puis notez que vous l’avez fait.

Tailscale privilégie une connexion directe entre les pairs et utilise ses serveurs relais lorsqu’il ne peut pas en établir une. Les relais fonctionnent, mais ajoutent de la latence. Un VPS avec une adresse publique est le cas le plus simple : autorisez les connexions UDP entrantes sur 41641, et la plupart des pairs se connecteront directement. Si ufw gère le firewall, les règles ufw réellement nécessaires sur un VPS présentent la syntaxe à utiliser.

Les règles d’accès constituent l’autre volet. Dans un tailnet par défaut, chacun de vos appareils peut accéder à tous les autres : une route approuvée fonctionne donc directement. Dès que vous écrivez une policy ACL, la destination d’une règle doit nommer la plage privée, car 10.0.0.20 n’est pas une adresse de tailnet et n’est pas couverte par les règles qui ciblent les adresses IP ou les tags du tailnet.

Enfin, déterminez si vous acceptez d’utiliser un serveur de coordination que vous n’administrez pas. Le control plane de Tailscale est un service hébergé. Vos clés restent sur vos machines, mais le compte et le fichier de policy sont hébergés sur ce service. L’utilisation de Headscale, le serveur de contrôle Tailscale auto-hébergé permet de conserver ces éléments sur votre propre VPS, au prix de sa maintenance. Si vous hésitez encore entre ce modèle et une configuration écrite manuellement, la comparaison entre WireGuard et Tailscale explique ce que la couche de coordination apporte et ce qu’elle implique.

FAQ

Quelle est la différence entre un subnet router et un exit node ?

Un subnet router annonce une plage d’adresses privées. Les appareils du tailnet peuvent ainsi atteindre des machines qui n’exécutent pas Tailscale. Un exit node s’annonce comme une route vers l’ensemble d’Internet. Un appareil envoie alors tout son trafic via l’adresse publique de ce nœud. Un même VPS peut assurer les deux fonctions. Il s’agit de flags distincts, --advertise-routes et --advertise-exit-node, et chacun nécessite sa propre approbation dans la console d’administration.

Pourquoi mon client Linux ignore-t-il la route de subnet annoncée ?

Les clients Linux n’acceptent pas les routes de subnet automatiquement. Vous devez le leur demander. Exécutez sudo tailscale set --accept-routes sur le client. Vérifiez ensuite avec ip route show table 52, et non avec ip route show. Tailscale installe les routes acceptées dans la table de routage 52 et les utilise via des règles de routage par stratégie. La table principale ne les affiche donc jamais, ce qui peut donner l’impression qu’une route fonctionnelle est absente.

Mon subnet ne fonctionne plus après un redémarrage. Que s’est-il passé ?

Le forwarding IP est probablement en cause. Une valeur définie avec sysctl -w ne survit pas à un redémarrage. Écrivez-la donc dans /etc/sysctl.d/99-tailscale.conf, puis vérifiez-la avec sysctl net.ipv4.ip_forward. Si le forwarding est actif et que la plage reste inaccessible, examinez le nœud dans la console d’administration. Par défaut, les clés de nœud expirent après 180 jours. Un subnet router dont la clé a expiré ressemble à un problème réseau plutôt qu’à un problème de compte.

Deux subnet routers peuvent-ils annoncer la même plage ?

Pas des plages identiques. Des plages qui se chevauchent avec des longueurs de préfixe différentes sont acceptées, et le préfixe le plus spécifique est prioritaire. Le failover demande toutefois de la prudence : lorsque le routeur qui détient le préfixe le plus spécifique est hors ligne, Tailscale ne bascule pas vers la route plus large. Le trafic est donc interrompu. Pour mettre en place une véritable paire de secours, faites annoncer les mêmes préfixes spécifiques par les deux routeurs.

Le nom d’hôte est résolu, mais la connexion expire. Pourquoi ?

La résolution DNS et le routage sont deux étapes distinctes. Un nom peut être résolu vers une adresse qui n’est couverte par aucune route approuvée. Le paquet sort alors via la passerelle par défaut du client. Exécutez ip route get <address> sur le client. Si la réponse n’inclut pas dev tailscale0, annoncez une plage qui couvre cette adresse et approuvez le nouveau préfixe dans la console d’administration.