Artykuł Serwery

SSH port forwarding - tunelowanie portow krok po kroku

SSH port forwarding (tunelowanie) przeciąga ruch portu przez zaszyfrowane połączenie SSH. Trzy tryby: lokalny ssh -L 8080:localhost:80 user@host (zdalna usługa na Twoim localhost), zdalny ssh -R (odwrotny, wystawia Twój port na serwerze) i dynamiczny ssh -D 1080 (SOCKS proxy). Tunel żyje, dopóki sesja SSH jest otwarta.

W skrócie: masz usługę, która słucha tylko lokalnie na zdalnym serwerze - bazę danych, panel admina, wewnętrzną aplikację - i chcesz się do niej dostać ze swojego laptopa, nie otwierając jej portu na cały internet. Zamiast wystawiać port na świat, owijasz go w tunel SSH, który i tak już masz. Poniżej rozkładam trzy tryby forwardingu, komendy gotowe do wklejenia dla Linuksa, macOS i Windows oraz najczęstsze pułapki, przez które tunel nie chce ruszyć.

Co to jest SSH port forwarding i po co go używać

SSH port forwarding owija połączenie TCP w istniejący, zaszyfrowany tunel SSH. Ruch wchodzi na jednym końcu (port po jednej stronie), przelatuje przez zaszyfrowany kanał i wychodzi na drugim - z perspektywy serwera SSH - żeby trafić do docelowej usługi. Dla samej usługi wygląda to tak, jakby połączenie przyszło lokalnie.

Konkret: po co to komu w codziennej robocie.

  • Połączenie do MySQL albo PostgreSQL na produkcji bez wystawiania portu 3306 czy 5432 na internet - łączysz się przez swój localhost, a baza cały czas słucha wyłącznie na serwerze.
  • Dostęp do panelu admina, który nasłuchuje tylko na 127.0.0.1 i celowo nie ma publicznego adresu.
  • Ominięcie NAT i firewalla, żeby dostać się do maszyny w domowym homelabie bez publicznego IP.
  • SOCKS proxy do przeglądania ruchu przez zaufany serwer w innej lokalizacji.

Kluczowa zaleta jest bezpieczeństwa: port docelowej usługi nie jest publicznie otwarty. Otwarty pozostaje tylko port SSH (domyślnie 22), który i tak masz wystawiony po to, żeby zarządzać serwerem. Tym różni się tunel SSH od przekierowania portu na routerze, które faktycznie wystawia usługę na świat ze wszystkimi tego konsekwencjami.

Jedno zastrzeżenie na start: standardowy forwarding tuneluje wyłącznie TCP. UDP tędy nie przejdzie - wracam do tego w troubleshootingu i w FAQ. Jeśli dopiero zaczynasz z samym protokołem, cały temat kluczy, konfiguracji i hardeningu rozkładam w przewodniku SSH od podstaw

To najczęściej używany wariant. Otwierasz port u siebie, a ruch, który na niego wpada, wychodzi po stronie serwera SSH i idzie do wskazanej usługi.

Składnia:

ssh -L [lokalny_port]:[host_docelowy]:[port_docelowy] user@serwer

Przykład - tunel do MySQL na produkcji:

ssh -L 3307:localhost:3306 user@serwer

Po odpaleniu łączysz się swoim klientem do localhost:3307, a ruch przelatuje tunelem i trafia do MySQL słuchającego na porcie 3306 na serwerze. Baza dalej nie jest widoczna z internetu.

Pułapka: localhost w tej komendzie to localhost z perspektywy serwera SSH, a nie Twojej maszyny. To najczęstszy błąd początkujących. Gdy usługa działa na innym hoście w sieci serwera, w miejsce localhost wpisujesz jego adres, na przykład ssh -L 3307:10.0.0.5:3306 user@serwer.

Remote / reverse port forwarding (-R)

Odwrotny kierunek. Tu wystawiasz usługę ze swojej strony tak, żeby serwer (albo ktoś, kto ma do niego dostęp) mógł do niej dotrzeć.

Składnia:

ssh -R [port_na_serwerze]:[host_lokalny]:[port_lokalny] user@serwer

Klasyczny scenariusz: masz dev server albo maszynę za NAT bez publicznego IP i chcesz udostępnić ją na zewnątrz. Reverse forwarding przebija się przez NAT, bo to Twoja maszyna inicjuje połączenie wychodzące do serwera, a nie odwrotnie.

Pułapka: domyślnie -R nasłuchuje tylko na 127.0.0.1 serwera, więc usługa jest dostępna wyłącznie z samego serwera. Żeby słuchał na wszystkich interfejsach i wpuścił ruch z zewnątrz, potrzebujesz GatewayPorts yes w konfiguracji sshd - opisuję to niżej.

Dynamic port forwarding / SOCKS (-D)

Zamiast jednego sztywnego celu tworzysz uniwersalny SOCKS proxy. Aplikacja, która potrafi korzystać z SOCKS-a (przeglądarka, wiele narzędzi CLI), przepuszcza przez niego cały swój ruch.

Składnia:

ssh -D 1080 user@serwer

To stawia SOCKS5 proxy na localhost:1080. Ustawiasz ten adres jako proxy w przeglądarce i od tej chwili cały jej ruch wychodzi do internetu przez serwer SSH. Praktyczne, gdy chcesz przeglądać przez zaufaną maszynę w innej lokalizacji albo dostać się do zasobów widocznych tylko z sieci serwera.

Krok po kroku - uruchomienie tunelu

Teraz od zera, z weryfikacją. Zakładam tunel lokalny jako przykład, ale schemat jest ten sam dla każdego trybu.

Linux i macOS

Krok po kroku:

  1. Odpal tunel lokalny: ssh -L 8080:localhost:80 user@serwer. Otwiera to port 8080 u Ciebie i kieruje go na port 80 po stronie serwera.
  2. Dorzuć flagi pomocnicze, gdy nie chcesz interaktywnej powłoki: -N (nie otwieraj sesji, tylko tunel), -f (zejdź w tło), -v (tryb debug, gdy coś nie gra). Gotowiec do pracy w tle: ssh -fNL 8080:localhost:80 user@serwer.
  3. Sprawdź, czy port słucha: ss -tlnp | grep 8080, albo po prostu otwórz http://localhost:8080 w przeglądarce.
  4. Zamknij tunel: przy sesji interaktywnej wpisz sekwencję ~., a dla tunelu w tle znajdź proces przez ps aux | grep ssh i zakończ go poleceniem kill.

Windows (OpenSSH i PuTTY)

Na Windowsie masz dwie drogi - konsolową i graficzną.

OpenSSH jest wbudowany w Windows 10 i 11, więc w PowerShell komenda wygląda dokładnie tak jak na Linuksie:

ssh -L 8080:localhost:80 user@serwer

PuTTY to droga graficzna, wygodna, gdy nie chcesz zapamiętywać składni. Krok po kroku: w oknie konfiguracji rozwiń Connection, potem SSH, dalej Tunnels. W polu Source port wpisz lokalny port (8080), w polu Destination wpisz cel w formacie host:port (na przykład localhost:80), kliknij Add, wróć do sekcji Session i połącz się przez Open. Tunel działa przez cały czas trwania sesji PuTTY.

Konfiguracja na stałe w ~/.ssh/config

Powtarzalne tunele lepiej trzymać w pliku konfiguracyjnym niż wyklikiwać albo wygrzebywać z historii basha. W ~/.ssh/config dopisz:

Host tunel-db
    HostName serwer
    User user
    LocalForward 3307 localhost:3306

Od tej chwili wystarczy ssh tunel-db, żeby postawić ten sam tunel. Pro tip admina: nazwane wpisy w configu to nie tylko wygoda - to też mniejsza szansa, że pomylisz port albo host przy ręcznym przepisywaniu długiej komendy.

Konfiguracja serwera - kiedy tunel nie ruszy bez zmian w sshd

Bardzo częsty scenariusz: komenda jest poprawna, a tunel i tak nie działa. Powód siedzi po stronie serwera, w pliku /etc/ssh/sshd_config.

  • AllowTcpForwarding yes musi być włączone, żeby forwarding w ogóle zadziałał. Na wielu zarządzanych i współdzielonych hostingach ta opcja jest domyślnie wyłączona ze względów bezpieczeństwa - i dlatego tunel odbija się od serwera.
  • GatewayPorts yes włączasz tylko wtedy, gdy remote forward w trybie -R ma nasłuchiwać na zewnętrznym interfejsie, a nie wyłącznie na 127.0.0.1 serwera.
  • Po każdej zmianie przeładuj usługę: sudo systemctl restart sshd.

Konkret: na hostingu współdzielonym zwykle nie ustawisz tych opcji, bo nie masz dostępu do sshd_config. To praktyczny argument za własnym VPS z pełną kontrolą nad SSH. Jeśli stoisz przed takim wyborem, w rankingu VPS porównuję dostępne opcje pod kątem tego, ile faktycznej kontroli nad serwerem i siecią dostajesz.

Częste błędy i pułapki

Zanim zaczniesz podejrzewać egzotyczne przyczyny, przejdź przez tę listę. W praktyce ponad 90% problemów z tunelem to jeden z poniższych stanów.

Objaw Przyczyna Rozwiązanie
channel ... open failed: administratively prohibited AllowTcpForwarding no na serwerze włącz forwarding w sshd_config i przeładuj sshd
tunel local łączy się, ale usługa nie odpowiada mylenie strony localhost (to perspektywa serwera) podaj właściwy host docelowy widziany z serwera
remote forward słucha tylko lokalnie na serwerze brak GatewayPorts yes włącz GatewayPorts yes w sshd_config
Address already in use lokalny port jest zajęty wybierz inny port albo zwolnij zajęty
Permission denied przy porcie poniżej 1024 porty uprzywilejowane wymagają roota użyj lokalnie portu powyżej 1024
UDP nie przechodzi tunelem SSH forwarding obsługuje tylko TCP zestaw UDP innym mechanizmem albo przez VPN
tunel pada po chwili bezczynności serwer zrywa nieaktywne połączenie ustaw ServerAliveInterval, do trwałych tuneli użyj autossh

Sprawdź jeszcze jedno, zanim obwinisz sam tunel: czy usługa docelowa w ogóle żyje i czy jej port jest otwarty. Szybki test portu opisuję we wpisie o poleceniu telnet do sprawdzania portów, a całość idealnie pasuje do dostępu do pojedynczej usługi - bazy, panelu, wewnętrznej aplikacji. Cena za tę prostotę: obsługuje tylko TCP, każdy port zestawiasz ręcznie, a tunel pada razem z sesją.

VPN działa na innym poziomie. Obejmuje cały ruch urządzenia, radzi sobie z TCP i UDP, trzyma się trwale i jest wygodny, gdy usług i osób jest wiele. Do tego dokłada warstwę prywatności w publicznych sieciach Wi-Fi, czego pojedynczy tunel do portu nie załatwi.

Kryterium Tunel SSH VPN
Zakres pojedyncze porty cały ruch urządzenia
Protokoły tylko TCP TCP i UDP
Trwałość do końca sesji stała, z auto-reconnect
Konfiguracja zero instalacji, per port osobny klient i serwer
Prywatność w publicznym Wi-Fi ograniczona pełna

Trade-off jest prosty: gdy potrzebujesz dostępu do jednej, dwóch usług - tunel SSH wygrywa prostotą. Gdy w grę wchodzi cała sieć, wielu użytkowników albo prywatność na publicznym hotspotcie, jeden tunel do portu to za mało i wtedy sięgasz po VPN. To nie jest wybór "lepsze kontra gorsze", tylko dobór narzędzia do zadania.

FAQ

Czym różni się local od remote port forwarding?

Flaga -L (local) przeciąga zdalną usługę na Twój localhost - łączysz się u siebie, ruch wychodzi po stronie serwera. Flaga -R (remote) działa odwrotnie: wystawia usługę z Twojej maszyny na serwerze, żeby ktoś po jego stronie mógł do niej dotrzeć. Kierunek ruchu to cała różnica.

Jak zrobić tunel SSH na Windows?

Masz dwie drogi. OpenSSH jest wbudowany w Windows 10 i 11, więc w PowerShell wpisujesz ssh -L 8080:localhost:80 user@serwer, identycznie jak na Linuksie. Alternatywnie PuTTY oferuje interfejs graficzny: sekcja Connection, SSH, Tunnels, gdzie podajesz Source port i Destination, klikasz Add i łączysz się.

Czy SSH tuneluje UDP?

Nie bezpośrednio. Standardowy SSH port forwarding obsługuje wyłącznie protokół TCP. Żeby przepchnąć UDP, potrzebujesz obejścia, na przykład narzędzia socat opakowującego UDP w połączenie TCP, albo pełnego VPN, który UDP obsługuje natywnie. Dla większości usług administracyjnych, opartych na TCP, to ograniczenie nie ma znaczenia.

Co to dynamic port forwarding (-D)?

Dynamic port forwarding tworzy SOCKS proxy poleceniem ssh -D 1080 user@serwer. Zamiast jednego sztywnego celu dostajesz uniwersalny proxy na localhost:1080. Aplikacja ustawiona na ten SOCKS - najczęściej przeglądarka - wypuszcza cały swój ruch przez serwer SSH, bez definiowania osobnego tunelu dla każdej usługi.

Dlaczego port forwarding nie działa mimo poprawnej komendy?

Najczęściej winna jest konfiguracja serwera: AllowTcpForwarding ustawione na no w sshd_config blokuje forwarding niezależnie od tego, jak dobra jest Twoja komenda. Druga częsta przyczyna to zajęty port lokalny sygnalizowany błędem Address already in use. Sprawdź te dwie rzeczy, zanim zaczniesz szukać dalej.

Jak utrzymać tunel po zamknięciu terminala?

Odpal go w tle flagami -fN, na przykład ssh -fN -L 8080:localhost:80 user@serwer. Do tuneli, które mają przetrwać zerwane połączenie i same się odtworzyć, użyj autossh. Na stałe najwygodniej wpisać LocalForward do ~/.ssh/config - wtedy tunel stawiasz jednym krótkim poleceniem.