Gérer ses tunnels SSH : enregistrer, démarrer et arrêter les redirections

Enregistrez chaque tunnel comme un bloc Host dans ~/.ssh/config avec LocalForward, RemoteForward ou DynamicForward, puis lancez-le par son nom avec ssh -f -N nom. Ajoutez ControlMaster, ControlPath et ControlPersist au bloc et vous pourrez l'arrêter avec ssh -O exit nom, sans chercher le processus. ssh -O forward et ssh -O cancel ajoutent ou retirent une redirection pendant que le tunnel tourne.

Mis à jour le . Exécuté avec OpenSSH 10.0 sur Debian 13 dans des conteneurs jetables : un client, un hôte de rebond et une cible avec un petit serveur HTTP.

Enregistrez chaque tunnel dans ~/.ssh/config

Retaper les options -L et -R à chaque fois, c'est la meilleure façon de mélanger les ports. Donnez plutôt un nom à chaque tunnel, dans son propre bloc Host :

Host db-tunnel
  HostName 203.0.113.10
  User deploy
  LocalForward 127.0.0.1:5432 127.0.0.1:5432
  ExitOnForwardFailure yes

Host dev-share
  HostName 203.0.113.10
  User deploy
  RemoteForward 127.0.0.1:9000 127.0.0.1:3000

Host socks
  HostName 203.0.113.10
  User deploy
  DynamicForward 127.0.0.1:1080

Chaque ligne est la forme « configuration » d'une option de ligne de commande : LocalForward correspond à -L, RemoteForward à -R et DynamicForward à -D. L'adresse et le port d'écoute viennent d'abord, puis un espace, puis la destination. Comme avec les options, c'est le serveur qui résout la destination d'une redirection locale : 127.0.0.1 y désigne donc le serveur lui-même. Si ces trois types sont nouveaux pour vous, commencez par les tunnels SSH local, distant et dynamique expliqués.

Utilisez un nom à part pour les tunnels, pas le Host avec lequel vous vous connectez tous les jours. Sinon chaque connexion tente d'ouvrir les mêmes ports, et la deuxième affiche Address already in use.

Lancez un tunnel par son nom

ssh -f -N db-tunnel

-N n'exécute aucune commande distante : la connexion ne transporte que les redirections. -f envoie ssh en arrière-plan après la connexion, si bien que la demande de phrase de passe ou de mot de passe vous parvient d'abord. Votre outil de base de données peut maintenant se connecter à 127.0.0.1:5432.

Avec ExitOnForwardFailure yes, un port déjà pris arrête ssh avec le code de sortie 255 au lieu de laisser une connexion sans tunnel. Voici ce que donne le lancement du même tunnel une seconde fois :

bind [127.0.0.1]:5432: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 5432
Could not request local forwarding.

Pour lancer plusieurs tunnels enregistrés d'un coup :

for t in db-tunnel socks; do ssh -f -N "$t"; done

Arrêtez un tunnel

Un tunnel en arrière-plan n'est qu'un processus ssh. Sans rien d'autre, on le retrouve et on le tue :

ps ax | grep '[s]sh -f -N db-tunnel'
pkill -f 'ssh -f -N db-tunnel'

pkill -f vise tout processus dont la ligne de commande contient ce texte. Dans nos tests, il a aussi tué le script shell qui avait lancé le tunnel, parce que le script contenait les mêmes mots. Un socket de contrôle est plus propre. Ajoutez trois lignes au bloc :

Host db-tunnel
  HostName 203.0.113.10
  User deploy
  LocalForward 127.0.0.1:5432 127.0.0.1:5432
  ExitOnForwardFailure yes
  ControlMaster auto
  ControlPath ~/.ssh/cm-%C
  ControlPersist yes

Le tunnel répond désormais aux commandes par son nom :

ssh -f -N db-tunnel
ssh -O check db-tunnel
ssh -O exit db-tunnel
Master running (pid=27)
Exit request sent.

Le socket permet aussi aux autres commandes ssh et scp vers db-tunnel de réutiliser la même connexion. Les détails sont dans le multiplexage SSH avec ControlMaster.

Ajoutez ou retirez une redirection sans vous reconnecter

Avec un socket de contrôle, vous pouvez modifier un tunnel en cours. La connexion et ses autres redirections restent actives :

ssh -O forward -L 127.0.0.1:8081:127.0.0.1:8000 db-tunnel
ssh -O cancel -L 127.0.0.1:8081:127.0.0.1:8000 db-tunnel

cancel exige exactement la même spécification que celle utilisée pour ajouter la redirection. Cela fonctionne aussi pour -R et -D. Avec -R 0:..., le serveur choisit un port libre et ssh -O forward l'affiche.

Gardez un tunnel enregistré actif

Un tunnel lancé avec -f vit aussi longtemps que sa connexion SSH. Une mise en veille, un changement de Wi-Fi ou un redémarrage du serveur y met fin. Ajoutez ces lignes au bloc pour que ssh repère une connexion morte en 45 secondes environ et se termine, au lieu de rester bloqué :

  ServerAliveInterval 15
  ServerAliveCountMax 3

Il faut ensuite quelque chose pour le relancer : une boucle, un gestionnaire de services ou autossh pour un tunnel SSH persistant.

Les erreurs qui cassent les tunnels enregistrés

  • Deux-points au lieu d'un espace. LocalForward 5432:127.0.0.1:5432 est le format de la ligne de commande, pas celui de la configuration. ssh répond Missing target argument, et dans notre test cette seule ligne fautive a empêché tous les hôtes du fichier de se connecter.
  • Écoute sur toutes les interfaces. LocalForward 0.0.0.0:5432 ... ou GatewayPorts yes permettent à d'autres machines de votre réseau d'utiliser le tunnel. Gardez 127.0.0.1, sauf si c'est voulu.
  • Deux tunnels sur le même port local. Seul le premier démarre. Donnez à chaque tunnel enregistré son propre port.
  • Redirection refusée par le serveur. Si le port s'ouvre mais que les connexions échouent avec administratively prohibited, le serveur a désactivé AllowTcpForwarding pour vous.

Questions

Comment voir quels tunnels SSH sont actifs ?

Lancez ps ax | grep '[s]sh -f -N' pour lister les processus ssh en arrière-plan avec leurs options. Pour un tunnel avec socket de contrôle, ssh -O check nom répond directement. Dans une session interactive, appuyez sur Entrée puis tapez ~# pour lister les connexions redirigées.

Une seule commande peut-elle lancer plusieurs tunnels ?

Oui. Placez plusieurs lignes LocalForward ou DynamicForward dans un même bloc Host : elles s'ouvrent toutes avec un seul ssh -f -N nom. Si un port est occupé et que ExitOnForwardFailure est activé, aucune ne reste ouverte.

Pourquoi mon tunnel enregistré s'arrête-t-il après une mise en veille ou un changement de réseau ?

Le tunnel vit dans une seule connexion SSH, qui meurt quand le réseau tombe. Ajoutez ServerAliveInterval pour que ssh s'en aperçoive, et relancez-le avec une boucle ou avec autossh.

Sources

Autres guides : Tunnels et hôtes de rebond

Tous les guides