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 circule en clair du client MySQL
jusqu'à localhost:3307, puis chiffré par SSH jusqu'au bastion, et de
nouveau en clair du bastion jusqu'à 192.168.1.100:3306.
Tunnel en arrière-plan
Section intitulée « Tunnel en arrière-plan »Un tunnel ouvert dans un terminal disparaît dès que ce terminal se ferme. Les
options -N et -f détachent le processus ssh du shell courant : la
main est rendue immédiatement et le tunnel survit à la fermeture de la fenêtre.
Contrepartie : plus aucun message d'erreur ne s'affiche, donc établissez
d'abord le tunnel au premier plan pour valider qu'il fonctionne, puis
relancez-le détaché.
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 »Retaper la redirection complète à chaque connexion finit par produire des
erreurs de port. La directive LocalForward dans ~/.ssh/config fige la
redirection dans le profil de l'hôte : la syntaxe y sépare le port local et
la cible par une espace, là où la ligne de commande les colle avec un
deux-points. Le fichier ne doit être inscriptible par personne d'autre que son
propriétaire, sinon OpenSSH refuse de l'utiliser ; 600 est la valeur
habituelle.
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.
Chromium via la ligne de commande :
chromium --proxy-server="socks5://localhost:1080"Firefox n'accepte aucune option de proxy en ligne de commande : le réglage
passe par about:preferences, section Paramètres réseau, en choisissant
« Configuration manuelle du proxy » puis en renseignant l'hôte SOCKS
localhost et le port 1080. Dans ce même écran, l'option qui délègue la
résolution DNS au proxy SOCKS v5 (préférence network.proxy.socks_remote_dns)
est indispensable : sans elle, les noms internes sont résolus par votre résolveur
local, qui ne les connaît pas.
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 »Le point important est que l'authentification finale se fait contre la cible,
pas contre le bastion. Le bastion ne sert que de relais TCP : il ne voit passer
que du trafic chiffré de bout en bout entre votre poste et 10.0.1.15. Un
administrateur du bastion ne peut donc pas lire votre session, contrairement à
un enchaînement de deux ssh où le second part depuis le bastion.
ssh -J bob@bastion.example.com alice@10.0.1.15Multi-sauts
Section intitulée « Multi-sauts »Les hôtes se déclarent dans l'ordre de traversée, séparés par des virgules, et le dernier argument reste la destination finale. Chaque saut ouvre une nouvelle session imbriquée : une latence de quelques centaines de millisecondes est normale sur trois niveaux. Si un saut intermédiaire échoue, le message d'erreur cite l'hôte fautif, ce qui permet de localiser la coupure sans tester chaque machine à la main.
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 »-J et -L se cumulent sans conflit parce qu'ils agissent à deux niveaux
différents : -J construit le chemin d'accès, -L ouvre la redirection une fois
arrivé. Le piège tient au localhost de la redirection : il désigne
10.0.2.20, l'hôte final, pas votre poste. Le -N évite d'ouvrir un shell
inutile sur la machine de production.
# 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 »La même chaîne écrite une fois dans le fichier de configuration se rejoue avec
ssh -N prod-db. La directive ProxyJump accepte la liste de sauts avec la
même syntaxe que l'option en ligne de commande, et LocalForward s'applique à
l'hôte final. Cette forme est celle à privilégier dès qu'un accès est répété :
les outils qui s'appuient sur SSH, comme scp, rsync ou git, lisent le même
fichier et héritent automatiquement du chemin.
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 »Le réflexe qui fait gagner le plus de temps : relancer la commande avec -v,
voire -vvv. La sortie indique à quelle étape le tunnel casse, et la
distinction est décisive. Un message émis par le client signale un problème
local (port occupé, clé refusée) ; un message préfixé channel N: vient du
serveur SSH et désigne un problème de joignabilité côté distant. Lisez le
tableau avec cette grille : la colonne « Cause probable » indique de quel côté
du tunnel chercher.
| 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 |
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À 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
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Les questions les plus posées sur les tunnels SSH, du choix entre -L, -R et
-D jusqu'à la persistance avec autossh.
Trois formes
| Option | Rôle |
|---|---|
-L |
Tunnel local : atteindre un service distant |
-R |
Tunnel distant : exposer un service local |
-D |
Proxy SOCKS dynamique : tout le trafic |
-L, tunnel local
ssh -L 3307:192.168.1.100:3306 bob@bastion.example.com
Redirige un port local vers une cible accessible depuis le serveur SSH. Usage type : atteindre une base MySQL derrière un bastion.-R, tunnel distant
ssh -R 8080:localhost:8080 bob@serveur.example.com
Redirige un port du serveur vers votre machine. Usage type : exposer un serveur de développement local.-D, proxy SOCKS
ssh -D 1080 bob@bastion.example.com
Ouvre un proxy SOCKS5 sur localhost:1080. Toute l'application configurée pour ce proxy sort par le serveur SSH.-J) remplace ProxyCommand pour traverser un bastion.ssh -J bob@bastion.example.com alice@10.0.1.15
Pourquoi ProxyJump
- L'authentification finale se fait contre la cible, pas contre le bastion.
- Le bastion ne sert que de relais TCP : il ne voit que du trafic chiffré de bout en bout.
- La syntaxe est plus courte et supporte les sauts multiples (hôtes séparés par des virgules).
ProxyCommand reste utile pour des cas exotiques (encapsulation via un binaire tiers), mais pour un simple rebond, ProxyJump est la référence.La nuance qui compte
Avec un tunnel-L, le trafic circule :- en clair du client jusqu'à
localhost; - chiffré par SSH jusqu'au bastion ;
- de nouveau en clair du bastion jusqu'à la cible.
AllowTcpForwarding et PermitOpen.Reconnexion automatique avec autossh
autossh -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 et délègue la détection de rupture aux options ServerAlive.Redirection figée dans ~/.ssh/config
Host bastion-mysql
HostName bastion.example.com
User bob
LocalForward 3307 192.168.1.100:3306
Le fichier doit être en 600 (inscriptible par le seul propriétaire), sinon OpenSSH le refuse. Ensuite : ssh -N bastion-mysql.Lancer détaché
ssh -N -f -L 3307:192.168.1.100:3306 bob@bastion.example.com
-N: pas de shell, juste le tunnel ;-f: passage en arrière-plan.
-f masque les messages d'erreur, établissez d'abord le tunnel au premier plan pour vérifier qu'il fonctionne, puis relancez-le détaché.Fermer
ps aux | grep "ssh -N"
kill <PID>
Le tunnel disparaît aussi automatiquement si vous l'aviez lancé dans un terminal que vous fermez (sans -f).| Critère | Tunnel SSH | VPN |
|---|---|---|
| Mise en place | Une commande | Serveur + clients à configurer |
| Portée | Un ou quelques services | Tout un réseau |
| Durée | Ponctuel | Permanent |
| Port entrant | Aucun (port 22 existant) | Souvent un port dédié |
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Durcir l'accès SSH : Restreindre les tunnels, désactiver le forwarding inutile, AllowTcpForwarding.