Un tunnel SSH permet de faire transiter un flux réseau à travers une connexion SSH chiffrée. Résultat : vous accédez à une base de données interne comme si elle était locale, vous exposez un service de développement sur un serveur public, ou vous faites passer tout votre trafic par un serveur distant. Pas besoin de VPN, pas de port supplémentaire à ouvrir.
C’est un objectif LFCS (domaine Networking — “Use SSH tunneling and port forwarding”).
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Créer un tunnel local (
-L) pour atteindre un service derrière un bastion - Créer un tunnel distant (
-R) pour rendre un service local accessible depuis l’extérieur - Créer un tunnel dynamique (
-D) comme proxy SOCKS pour tout le trafic - Utiliser ProxyJump pour traverser un ou plusieurs hôtes intermédiaires
- Persister les tunnels dans
~/.ssh/config - Diagnostiquer un tunnel bloqué
Dans quel contexte ?
Section intitulée « Dans quel contexte ? »Les tunnels SSH servent quand le réseau empêche un accès direct : une base de données sur un réseau privé inaccessible depuis l’extérieur, un service web interne visible seulement depuis un bastion, un environnement de développement local à partager temporairement avec un collègue. En une commande, SSH crée un canal chiffré qui contourne ces restrictions sans modifier les règles de pare-feu du serveur cible.
Tunnel local (-L) — atteindre un service distant
Section intitulée « Tunnel local (-L) — atteindre un service distant »Un tunnel local redirige un port de votre machine vers un port sur (ou accessible depuis) le serveur SSH.
Syntaxe :
ssh -L [adresse_locale:]port_local:hôte_cible:port_cible user@bastionExemple : accéder à MySQL derrière un bastion
Section intitulée « Exemple : accéder à MySQL derrière un bastion »Vous voulez vous connecter à un serveur MySQL sur 192.168.1.100:3306, accessible uniquement depuis le bastion bastion.example.com :
ssh -L 3307:192.168.1.100:3306 bob@bastion.example.comEnsuite, depuis votre machine locale :
mysql -h 127.0.0.1 -P 3307 -u root -pMySQL répond comme s’il était local — le trafic passe en clair du client MySQL → localhost:3307, puis chiffré via SSH jusqu’à 192.168.1.100:3306.
Tunnel en arrière-plan
Section intitulée « Tunnel en arrière-plan »Pour ne pas monopoliser un terminal :
ssh -N -f -L 3307:192.168.1.100:3306 bob@bastion.example.com-N: ne pas ouvrir de shell, juste le tunnel-f: passer en arrière-plan avant l’exécution
Pour fermer le tunnel :
# Trouver le PIDps aux | grep "ssh -N"kill <PID>Persistance dans ~/.ssh/config
Section intitulée « Persistance dans ~/.ssh/config »Host bastion-mysql HostName bastion.example.com User bob LocalForward 3307 192.168.1.100:3306Puis simplement :
ssh -N bastion-mysqlTunnel distant (-R) — exposer un service local
Section intitulée « Tunnel distant (-R) — exposer un service local »Un tunnel distant redirige un port sur le serveur SSH vers un port de votre machine locale. C’est l’inverse du tunnel local.
Syntaxe :
ssh -R [adresse_distante:]port_distant:hôte_local:port_local user@serveurExemple : partager un serveur de développement local
Section intitulée « Exemple : partager un serveur de développement local »Vous avez un serveur de développement sur localhost:8080 et vous voulez le rendre accessible via serveur.example.com:8080 :
ssh -R 8080:localhost:8080 bob@serveur.example.comToute personne qui accède à http://serveur.example.com:8080 voit votre serveur local.
Tunnel dynamique (-D) — proxy SOCKS
Section intitulée « Tunnel dynamique (-D) — proxy SOCKS »Un tunnel dynamique transforme la connexion SSH en proxy SOCKS. Au lieu de rediriger un seul port vers une cible fixe, tout le trafic envoyé au proxy est acheminé via le serveur SSH, qui décide de la destination.
Syntaxe :
ssh -D 1080 bob@bastion.example.comEnsuite, configurez votre application pour utiliser localhost:1080 comme proxy SOCKS5.
Firefox via la ligne de commande :
firefox --proxy-server="socks5://localhost:1080"curl avec SOCKS :
curl --socks5 localhost:1080 http://service-interne.example.com/api/statusProxyJump — traverser plusieurs hôtes
Section intitulée « ProxyJump — traverser plusieurs hôtes »ProxyJump (-J) établit la connexion via un ou plusieurs hôtes intermédiaires. C’est la méthode moderne, plus sûre que ProxyCommand, et c’est un tunnel implicite.
Cas simple : bastion → cible
Section intitulée « Cas simple : bastion → cible »ssh -J bob@bastion.example.com alice@10.0.1.15Multi-sauts
Section intitulée « Multi-sauts »ssh -J bob@bastion.example.com,carol@10.0.1.5 alice@10.0.2.20Combiner ProxyJump et tunnel local
Section intitulée « Combiner ProxyJump et tunnel local »# Accéder à la BDD sur 10.0.2.20 via deux hôtes intermédiairesssh -J bob@bastion.example.com,carol@10.0.1.5 \ -L 5432:localhost:5432 \ alice@10.0.2.20 -NDans ~/.ssh/config
Section intitulée « Dans ~/.ssh/config »Host prod-db HostName 10.0.2.20 User alice ProxyJump bob@bastion.example.com,carol@10.0.1.5 LocalForward 5432 localhost:5432Tunnels persistants avec autossh
Section intitulée « Tunnels persistants avec autossh »Pour un tunnel qui se reconnecte automatiquement si la connexion est perdue :
# Installationsudo apt install autossh # Debian/Ubuntusudo dnf install autossh # RHEL/Fedora
# Tunnel local persistantautossh -M 0 -N -f \ -o "ServerAliveInterval 30" \ -o "ServerAliveCountMax 3" \ -L 3307:192.168.1.100:3306 \ bob@bastion.example.com-M 0 désactive le port de monitoring d’autossh et délègue la détection de rupture aux options ServerAlive.
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Action |
|---|---|---|
bind: Address already in use | Port local déjà utilisé | Changer le port local ou tuer le processus occupant ce port |
| Tunnel établi mais connexion refusée | GatewayPorts no côté serveur | Ajouter GatewayPorts yes dans sshd_config (tunnel -R) |
Tunnel -D : les applications ne passent pas | Proxy SOCKS mal configuré dans l’app | Vérifier que l’app utilise SOCKS5, pas SOCKS4 ou HTTP |
| Tunnel se ferme après quelques minutes | Timeout SSH côté serveur | Ajouter ServerAliveInterval 60 dans ~/.ssh/config ou utiliser autossh |
channel 2: open failed: connect failed | Le serveur cible du tunnel est injoignable depuis le bastion | Vérifier que 192.168.1.100:3306 est accessible depuis le bastion, pas depuis votre machine |
ProxyJump : Permission denied | Clé SSH absente sur l’hôte intermédiaire | Copier la clé sur chaque hôte intermédiaire ou activer ForwardAgent yes |
À retenir
Section intitulée « À retenir »-L port_local:cible:port_cible: atteindre un service distant comme s’il était local-R port_distant:cible:port_cible: exposer un service local sur le serveur SSH-D port: proxy SOCKS pour tout le trafic d’une application-N -f: tunnel sans shell, en arrière-plan- ProxyJump remplace
ProxyCommandet supporte les sauts multiples - Pour les tunnels critiques,
autosshassure la reconnexion automatique