357 votes

Comment maintenir de manière fiable un tunnel SSH ouvert ?

J'utilise un tunnel SSH depuis le travail pour contourner divers pare-feu idiots (cela ne pose pas de problème avec mon patron :)). Le problème est que, après un certain temps, la connexion ssh se fige généralement et le tunnel est interrompu.

Si je pouvais au moins surveiller le tunnel automatiquement, je pourrais le redémarrer lorsqu'il se fige, mais je n'ai même pas trouvé de moyen de le faire.

Des points bonus pour celui qui peut me dire comment empêcher ma connexion ssh de se figer, bien sûr !

0 votes

Est-ce que votre tunnel est mort à cause de l'inactivité? J'ai eu ce problème lorsque je transférais des ports depuis mon téléphone, alors j'ai finalement commencé à générer des commandes factices sur la connexion pour le maintenir "en vie" en utilisant la commande watch comme ceci : watch -n1 60 echo "wiiiii". Le tunnel ne mourra pas à moins que le réseau ne soit coupé ou que vous ne l'utilisiez pas.

2 votes

16voto

Matt Conway Points 91

Pour ceux qui ne veulent pas (ou) ne peuvent pas utiliser AutoSSH...

J'ai un NAS auquel je veux accéder depuis internet, je ne peux pas utiliser le redirection de ports car mon FAI utilise le CGNAT (mon adresse IP publique n'est pas vraiment mon adresse IP publique, je suis derrière un autre routeur sur lequel je n'ai aucun contrôle). Par conséquent, pour accéder à mon NAS, j'ai un VPS (que je loue chez OVH pour un coût mensuel très faible) et qui a une adresse IP publique fixe. Donc pour accéder à mon NAS depuis internet, je dois simplement créer un tunnel SSH entre mon NAS et mon VPS, qui reste fiablement ouvert en permanence (pour un accès 24 heures sur 24). Cependant, j'ai souffert du tunnel SSH qui était "fermé" en raison de l'inactivité (malgré le processus ssh restant actif). Cela peut facilement être surmonté en demandant au client (dans mon cas, le VPS) de "pinguer" le serveur (dans mon cas, le NAS) en utilisant l'option keep alive.

Pour créer un Tunnel SSH, j'émet la commande suivante (à partir du NAS) :

ssh -NT -o ServerAliveInterval=60 -o ServerAliveCountMax=10 -o ExitOnForwardFailure=yes -i /var/services/homes/foouser/.ssh/id_rsa -R 8080:localhost:80 -R 4443:localhost:443 foouser@

Pour expliquer cette commande :

  • -N - Ne pas exécuter de commande à distance ; utile pour simplement faire de la redirection de ports.
  • -T - Désactiver l'allocation de pseudo-tty.
  • -R 8080:localhost:80 - Spécifie que le port donné sur l'hôte distant (serveur) doit être redirigé vers l'hôte et le port donnés sur le côté local. Dans ce cas, cela signifie rediriger le port 80 du serveur distant vers le port 8080 du client.
  • -i /chemin/vers/clé - Spécifie le chemin de la clé ssh utilisée pour établir la session ssh, sans cela vous devrez entrer le nom d'utilisateur (si non fourni) et le mot de passe pour établir la session ssh.
  • ServerAliveInterval - le nombre de secondes que le client attendra avant d'envoyer un message "server alive" au serveur pour maintenir la connexion active.
  • ServerAliveCountMax - le nombre de messages "server alive" qui peuvent être envoyés sans réponse du serveur. Si ce seuil est atteint, ssh se déconnectera du serveur, mettant fin à la session.
  • ExitOnForwardFailure - si défini sur "yes", la connexion sera interrompue si ssh ne peut pas configurer toutes les redirections de port dynamiques, tunnel, locales et distantes demandées (par exemple, si l'une ou l'autre des extrémités ne peut pas se lier et écouter sur un port spécifié).
  • foouser@ - Spécifie le compte utilisateur foouser utilisé pour établir la session ssh de redirection de port distant avec le serveur .

Il vaut également la peine d'ajouter quelques options de configuration ssh au serveur (dans mon cas, sur mon VPS) ; en ajoutant le fichier suivant s'il n'existe pas déjà :

[foouser@vps ~]$ cat /home/foouser/.ssh/config
Host *
    TCPKeepAlive yes
    ClientAliveInterval 30
    ClientAliveCountMax 9999

Note : vous pouvez remplacer le * (qui signifie appliquer cette configuration à "tous les hôtes") par un hôte spécifique - Dans mon cas, mon NAS (c'est-à-dire l'hôte qui se connecte à mon VPS) est derrière mon routeur ; l'adresse IP publique de mon routeur change fréquemment car elle est attribuée en DHCP (par mon FAI) donc je suis resté avec "tous les hôtes".

Processus SystemD (NAS Synology)

J'ai également cette commande (celle qui démarre le tunnel SSH en tant que processus systemd, si cela intéresse quelqu'un, voici le script :

foouser@nas:~$ cat /etc/systemd/system/sshtunnel-web.service 
[Unit]
Description=Tunnel SSH pour WebStation
After=network.target

[Service]
Restart=always
RestartSec=1
User=foouser
ExecStart=/bin/ssh \
    -NT \
    -o ServerAliveInterval=60 \
    -o ServerAliveCountMax=10 \
    -o ExitOnForwardFailure=yes \
    -i /var/services/homes/foouser/.ssh/id_rsa \
    -R 8080:localhost:80 \
    -R 4443:localhost:443 \
    foouser@

[Install]
WantedBy=multi-user.target

Pour démarrer et activer le service Tunnel SSH :

foouser@nas:~$ sudo systemctl daemon-reload
foouser@nas:~$ sudo systemctl start sshtunnel-web.service
foouser@nas:~$ sudo systemctl enable sshtunnel-web.service

Cela a bien fonctionné pour moi pendant plusieurs mois. Cela inclut une fiabilité sur plusieurs redémarrages de mon routeur domestique, du serveur VPS et du NAS.

0 votes

Vous avez oublié d'ajouter StartLimitIntervalSec=0 à la section [Unit]. Cela désactive la fonction de limitation de fréquence de systemd, qui empêche le redémarrage des services s'ils échouent trop rapidement. Cela pourrait se produire si le périphérique du réseau local est temporairement hors service, et ssh se fermerait immédiatement avec une erreur de connexion refusée.

14voto

user2793784 Points 131

Il me semble que vous interprétez mal ServerAliveCountMax. D'après ce que je comprends de la documentation, il s'agit du nombre de messages de présence du serveur qui peuvent rester sans réponse sans que la connexion soit interrompue. Ainsi, dans les cas dont nous discutons ici, le fait de le régler sur une valeur élevée garantira simplement qu'une connexion bloquée ne sera pas détectée et interrompue !

Il suffit simplement de définir ServerAliveInterval pour résoudre le problème avec un pare-feu qui oublie la connexion, et laisser ServerAliveCountMax bas permettra à l'extrémité d'origine de détecter l'échec et de se terminer en cas de connexion qui échoue de toute façon.

Ce que vous voulez, c'est 1) que la connexion reste ouverte en permanence dans des circonstances normales, 2) détecter la panne de connexion et que l'extrémité d'origine se termine en cas de défaillance, et 3) que la commande ssh soit réémise à chaque fois qu'elle se termine (la manière de faire cela dépend grandement de la plate-forme, le script "while true" suggéré par Jawa est une façon, sur OS X j'ai en fait mis en place un élément launchd).

12voto

H. Kocher Points 138

Toujours utiliser l'option SSH ServerAliveInterval en cas de problèmes de tunnel générés par des sessions NAT expirées.

Toujours utiliser une méthode de redémarrage en cas de perte totale de la connectivité, vous avez au moins trois options ici :

  • programme autossh

  • script bash (while true do ssh ...; sleep 5; done) ne pas supprimer la commande sleep, ssh peut échouer rapidement et vous relancerez trop de processus

  • /etc/inittab, pour avoir accès à une boîte expédiée et installée dans un autre pays, derrière un NAT, sans redirection de port vers la boîte, vous pouvez le configurer pour créer un tunnel ssh de retour vers vous :

    tun1:2345:respawn:/usr/bin/ssh -i /chemin/vers/rsaKey -f -N -o "ServerAliveInterval 180" -R 55002:localhost:22 utilisateur@adressepublique 'sleep 365j'
  • script upstart sur Ubuntu, où /etc/inittab n'est pas disponible :

    start on net-device-up IFACE=eth0
    stop on runlevel [01S6]
    respawn
    respawn limit 180 900
    exec ssh -i /chemin/vers/rsaKey -N -o "ServerAliveInterval 180" -R 55002:localhost:22 utilisateur@adressepublique
    post-stop script
        sleep 5
    end script

ou toujours utiliser les deux méthodes.

1 votes

+1 pour l'option en ligne au cas où vous ne le voulez pas pour toutes vos connexions SSH

0 votes

Vous écrivez "au cas où la connectivité tomberait complètement en panne". Maintenant je ne comprends pas, quels problèmes autossh résoud-il par lui-même, et lesquels ne le sont pas? Je pensais bien sûr qu'il s'occuperait de toute connexion interrompue, comme débrancher le câble pendant quelques heures, mais peut-être pas?

10voto

nachopro Points 181

J'ai résolu ce problème avec ceci:

Modifier

~/.ssh/config

Et ajouter

ServerAliveInterval 15
ServerAliveCountMax 4

Conformément à la page de manuel pour ssh_config:

ServerAliveCountMax
         Définit le nombre de messages de serveur en vie (voir ci-dessous) qui peuvent être
         envoyés sans que ssh(1) ne reçoive de messages du serveur.
         Si ce seuil est atteint alors que des messages de serveur en vie sont
         envoyés, ssh se déconnectera du serveur, mettant fin à la
         session. Il est important de noter que l'utilisation de messages de serveur en vie
         est très différente de TCPKeepAlive (ci-dessous). Les messages de serveur en vie
         sont envoyés à travers le canal crypté et ne peuvent donc pas être falsifiés. L'option TCP keepalive activée par
         TCPKeepAlive est falsifiable. Le mécanisme de serveur en vie est utile lorsque le client ou le serveur dépendent de la connaissance de
         l'inactivité d'une connexion.

         La valeur par défaut est 3. Par exemple, si ServerAliveInterval
         (voir ci-dessous) est défini à 15 et que ServerAliveCountMax est laissé à la
         valeur par défaut, si le serveur devient non réactif, ssh se déconnectera
         après environ 45 secondes. Cette option s'applique uniquement à la version du protocole
         2.

 ServerAliveInterval
         Définit un intervalle de temps en secondes après lequel si aucune donnée n'a été
         reçue du serveur, ssh(1) enverra un message à travers
         le canal crypté pour demander une réponse du serveur. Le
         défaut est 0, indiquant que ces messages ne seront pas envoyés au
         serveur. Cette option s'applique uniquement à la version du protocole
         2.

0 votes

Toutes les 15 secondes semblent assez souvent pour pinguer le serveur.

0 votes

@Lambart mais si la connexion est vraiment instable et tombe souvent, elle détecte au moins une connexion morte et donne la possibilité de réessayer plus tôt.

0 votes

Ne fonctionne pas sur macOS 10.15.3

8voto

jcomeau_ictx Points 771

ExitOnForwardFailure yes est un bon complément aux autres suggestions. S'il se connecte mais ne peut pas établir la redirection de port, il vous est tout aussi inutile que s'il n'avait pas du tout connecté.

0 votes

Il s'agit d'une très bonne idée. Même autossh est inutile si la connexion précédente est perçue comme expirée plus tôt du côté distant que du côté hôte local, car dans ce cas, l'hôte local essaiera de se reconnecter, mais le transfert ne peut pas être établi car le port est toujours ouvert.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X