kalvn logo kalvn

Les tunnels SSH ou comment accéder au localhost de son propre server

Je viens de découvrir une astuce très intéressante avec SSH : accéder au localhost de son serveur VPS depuis son ordinateur comme si le serveur tournait sur l'ordinateur, à l'aide du tunneling SSH.

Pourquoi faire me direz-vous ?

Je vois deux usages principaux :

Certains outils hébergeables sur un VPS sont accompagnés d'une console web qui permet d'administrer l'outil. Cependant, exposer cette console directement depuis votre serveur présente un risque de sécurité. Si la personne qui l'a développée n'a pas été suffisamment consciencieuse, vous sacrifiez alors la sécurité de votre serveur pour un peu de confort (les consoles web sont en général plus agréables à utiliser que la ligne de commande ou les fichiers YAML de config à rallonge). Grace au tunneling SSH, vous pouvez faire tourner la console mais uniquement en local, de telle sorte qu'elle ne soit accessible que par quelqu'un qui dispose d'un accès SSH à votre serveur (vous uniquement donc, a priori).

L'autre cas d'utilisation, c'est tout simplement de débuguer. Il est parfois utilise de pouvoir accéder à des resources locales à votre serveur sans les exposer directement.

Comment ça fonctionne ?

Il y a une unique commande à retenir :

ssh -L port_local:host_cible_depuis_le_serveur:port_distant user@ip

où :

Exemple avec wg-easy qui permet de créer un serveur Wireguard (c'est un protocol VPN) sur votre serveur :

ssh -L 51821:localhost:51821 user@ip

51821 est le port sur lequel est exposée la console web.

Une fois le tunnel établi, il vous suffit d'ouvrir http://localhost:51821 sur votre ordinateur, et vous verrez la console web comme si vous étiez sur votre serveur.

Limiter l'exposition d'un service avec Docker

Si vous utilisez Docker pour exécuter vos applications, il faut adapter la configuration pour n'exposer un port sensible qu'à localhost. Exemple avec wg-easy:

compose.yaml
services:
  wg-easy:
    image: ghcr.io/wg-easy/wg-easy:latest
    container_name: wg-easy
    restart: unless-stopped
    volumes:
      - ./wg-easy-data:/etc/wireguard
    ports:
      - "51820:51820/udp"     # trafic VPN — seul port exposé publiquement
      - "127.0.0.1:51821:51821/tcp"  # UI web : exposée en local uniquement 
    environment:
      - PORT=51821
      - HOST=0.0.0.0
      - WG_HOST=X.X.X.X  # Adresse IP publique de votre serveur
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv4.ip_forward=1
    env_file:
      - .env

Le même principe est applicable (mais moins lisible) si vous utilisez directement docker run.