Lokalen Port über SSH tunneln: Beispiele für den Alltag

Einen lokalen Port über SSH tunneln klingt erstmal nach etwas, das man nur macht, wenn im Keller ein Rack brummt und man freiwillig Logdateien liest. In der Praxis ist ein SSH Tunnel aber einfach ein sehr nützliches Werkzeug: Du leitest einen Port von deinem Rechner über eine verschlüsselte SSH-Verbindung zu einem Dienst auf einem Server weiter.

Ich nutze das gerne, wenn ein Webinterface nur auf 127.0.0.1 lauscht, ein Dienst nicht öffentlich erreichbar sein soll oder ich kurz auf etwas im internen Netz eines Servers zugreifen muss. Ohne VPN, ohne extra Freigabe in der Firewall und ohne das klassische „Ich mache den Port nur kurz auf“ Drama. Spoiler: Kurz bleibt selten kurz.

🧠 Was ein SSH Tunnel macht

Bei einem lokalen SSH Tunnel öffnet SSH auf deinem Rechner einen lokalen Port. Alles, was du an diesen lokalen Port schickst, wird durch die SSH-Verbindung zum Zielserver transportiert. Der Zielserver verbindet sich dann von seiner Seite aus mit dem gewünschten Zielhost und Zielport.

Die Grundform sieht so aus:

ssh -L LOKALER_PORT:ZIEL_HOST:ZIEL_PORT benutzer@ssh-server

Die drei Teile hinter -L sind wichtig:

  • LOKALER_PORT ist der Port auf deinem eigenen Rechner.
  • ZIEL_HOST ist der Host aus Sicht des SSH-Servers.
  • ZIEL_PORT ist der Port des eigentlichen Dienstes.

Der Punkt mit „aus Sicht des SSH-Servers“ ist der Teil, an dem es gerne kurz knirscht. Wenn du 127.0.0.1 als Zielhost einträgst, meinst du nicht deinen lokalen Rechner, sondern 127.0.0.1 auf dem Server, auf dem SSH endet.

🔌 Lokalen Port mit SSH tunneln

Angenommen, auf deinem Server läuft ein internes Webinterface auf 127.0.0.1:8080. Direkt von außen kommst du nicht dran, weil es bewusst nur lokal auf dem Server lauscht. Genau dafür ist ein lokaler SSH Tunnel sehr angenehm.

ssh -N -L 8080:127.0.0.1:8080 root@mein-server.example

Danach öffnest du lokal im Browser:

http://127.0.0.1:8080

Das -N sorgt dafür, dass kein Remote-Befehl ausgeführt wird. Die SSH-Verbindung bleibt einfach offen und transportiert nur den Tunnel. Das ist für reine Portweiterleitungen meistens genau richtig.

Beispiel aus meinem Test

Ich habe das Ganze auf einem Testserver mit einem kleinen Webserver geprüft. Der Dienst lief dort nur auf 127.0.0.1:18080 und war damit von außen nicht direkt erreichbar.

python3 -m http.server 18080 --bind 127.0.0.1 --directory /tmp/ssh-tunnel-demo

Den Tunnel habe ich dann lokal auf Port 18081 gelegt:

ssh -N -o ExitOnForwardFailure=yes -L 18081:127.0.0.1:18080 root@10.0.1.92

Der lokale Abruf kam dann sauber durch den Tunnel zurück:

curl http://127.0.0.1:18081/
SSH Tunnel Demo auf dev02

Damit ist bewiesen: Der Dienst muss nicht öffentlich erreichbar sein. Es reicht, wenn der SSH-Server ihn erreichen kann.

🧰 Praktische SSH Tunnel Beispiele

Je nach Situation ändert sich nur der mittlere Teil hinter -L. Das Grundprinzip bleibt gleich.

Webinterface auf dem Server öffnen

Wenn ein Dienst auf dem SSH-Server selbst läuft, nutzt du als Zielhost meistens 127.0.0.1:

ssh -N -L 9000:127.0.0.1:9000 root@mein-server.example

Lokal rufst du anschließend http://127.0.0.1:9000 auf.

Dienst im entfernten Netzwerk erreichen

Der Zielhost muss nicht zwingend der SSH-Server selbst sein. Wenn dein SSH-Server ein internes System erreichen kann, kannst du auch dorthin tunneln. Praktisch ist das zum Beispiel bei Admin-Oberflächen im Homelab.

ssh -N -L 8443:10.0.1.11:8006 root@jump-host.example

In diesem Beispiel öffnest du lokal https://127.0.0.1:8443. Der SSH-Server verbindet sich intern zu 10.0.1.11:8006. Dein eigener Rechner muss diese interne IP nicht direkt erreichen können.

Datenbank lokal erreichbar machen

Auch für Datenbanken ist ein SSH Tunnel sehr praktisch. So kannst du ein lokales Tool nutzen, ohne den Datenbank-Port öffentlich freizugeben.

ssh -N -L 5433:127.0.0.1:5432 root@db-server.example

Dein lokales Datenbank-Tool verbindet sich dann mit 127.0.0.1 und Port 5433. Auf dem Server landet die Verbindung bei PostgreSQL auf 127.0.0.1:5432.

⚙️ Tunnel im Hintergrund starten

Auf Linux und macOS kannst du den Tunnel mit -f in den Hintergrund schicken. Ich kombiniere das gerne mit ExitOnForwardFailure, damit SSH direkt abbricht, wenn der Port nicht gebunden werden kann.

ssh -f -N -o ExitOnForwardFailure=yes -L 18081:127.0.0.1:18080 root@10.0.1.92

Unter Windows kannst du den Tunnel zum Beispiel in einem eigenen Terminal offen lassen. Wenn du PowerShell nutzen möchtest, geht auch ein versteckter Prozess:

Start-Process ssh -ArgumentList @(
  '-N',
  '-o', 'ExitOnForwardFailure=yes',
  '-L', '18081:127.0.0.1:18080',
  'root@10.0.1.92'
) -WindowStyle Hidden

Für den Alltag ist mir ein normal geöffnetes Terminal oft lieber, weil man sofort sieht, ob die Verbindung noch steht. Versteckte Prozesse sind praktisch, aber auch eine gute Methode, sich später selbst zu fragen, warum Port 18081 schon belegt ist.

📝 SSH Config statt langer Befehle

Wenn du denselben Tunnel öfter brauchst, gehört er in die SSH-Konfiguration. Das spart Tipparbeit und reduziert Fehler. Die Datei liegt normalerweise unter ~/.ssh/config.

Host dev02-webdemo
    HostName 10.0.1.92
    User root
    LocalForward 18081 127.0.0.1:18080
    ExitOnForwardFailure yes
    ServerAliveInterval 30

Danach startest du den Tunnel nur noch so:

ssh -N dev02-webdemo

Das ist deutlich angenehmer als lange Befehle aus alten Notizen zu kopieren. Alte Notizen sind gut. Alte Notizen mit falschen Ports sind Charakterbildung.

🌐 SOCKS Proxy über SSH

Wenn du nicht nur einen festen Port brauchst, sondern mehrere Ziele flexibel über den SSH-Server erreichen möchtest, ist ein dynamischer Tunnel spannend. Dafür gibt es -D. SSH stellt dir dabei lokal einen SOCKS-Proxy bereit.

ssh -N -D 1080 root@10.0.1.92

Ein Test mit curl sieht dann so aus:

curl --socks5-hostname 127.0.0.1:1080 http://127.0.0.1:18080/

Wichtig ist hier --socks5-hostname. Damit wird auch die Namensauflösung über den SOCKS-Proxy gemacht. Das ist besonders nützlich, wenn interne Hostnamen nur aus Sicht des SSH-Servers funktionieren.

🔁 Remote Forwarding als Gegenrichtung

Der Vollständigkeit halber: Es gibt auch die Gegenrichtung. Mit -R öffnest du einen Port auf dem entfernten Server und leitest ihn zu deinem lokalen Rechner weiter.

ssh -N -R 9000:127.0.0.1:3000 root@mein-server.example

Das ist praktisch, wenn du eine lokale Entwicklungsumgebung kurz auf einem entfernten Server verfügbar machen möchtest. Je nach SSH-Server-Konfiguration kann dafür AllowTcpForwarding oder GatewayPorts relevant werden. Also bitte nicht blind auf Produktivsystemen herumdrehen.

🔒 Sicherheit und typische Fehler

SSH Tunneling ist sicher, solange du verstehst, was du freigibst. Der Tunnel verschlüsselt die Verbindung zwischen dir und dem SSH-Server. Er macht den Zieldienst aber nicht automatisch sicherer. Wenn du eine unsichere Admin-Oberfläche tunnelst, bleibt sie eine unsichere Admin-Oberfläche. Nur eben nicht öffentlich erreichbar.

  • Nutze SSH-Keys statt Passwörter, wo es möglich ist.
  • Binde lokale Tunnel nur an 127.0.0.1, wenn niemand anders im LAN darauf zugreifen soll.
  • Wenn ein lokaler Port belegt ist, nimm einfach einen anderen lokalen Port.
  • Setze ExitOnForwardFailure=yes, damit Fehler direkt sichtbar werden.
  • Prüfe bei Problemen, ob der Zielhost aus Sicht des SSH-Servers erreichbar ist.

Wenn du den Tunnel bewusst im LAN anbieten willst, kannst du den lokalen Bind-Host angeben:

ssh -N -L 0.0.0.0:18081:127.0.0.1:18080 root@10.0.1.92

Damit lauscht dein lokaler Rechner auf allen Interfaces. Das kann sinnvoll sein, sollte aber eine bewusste Entscheidung sein. Firewall, Netzwerk und Mitmenschen mit neugierigen Browsern denken sonst gerne mit.

🧯 Troubleshooting

Wenn der Tunnel nicht funktioniert, liegt es meistens an einem dieser Punkte:

  • Lokaler Port belegt: Nutze zum Beispiel 18081 statt 8080.
  • Zielhost falsch gedacht: 127.0.0.1 hinter -L bezieht sich auf die Server-Seite.
  • Dienst lauscht nicht: Prüfe auf dem Server mit ss -ltnp, ob der Zielport offen ist.
  • SSH darf kein Forwarding: Auf dem Server kann AllowTcpForwarding in der SSH-Konfiguration eingeschränkt sein.
  • Firewall blockiert intern: Wenn du zu einem anderen Host im Servernetz tunnelst, muss der SSH-Server diesen Host erreichen können.

Zum Debuggen kannst du SSH etwas gesprächiger machen:

ssh -vvv -N -L 18081:127.0.0.1:18080 root@10.0.1.92

Die Ausgabe ist nicht schön, aber hilfreich. SSH erzählt dann ziemlich genau, an welcher Stelle es klemmt.

✅ Fazit

SSH Tunnels sind eines dieser Werkzeuge, die man nicht täglich braucht, aber im richtigen Moment sehr dankbar aus der Werkzeugkiste zieht. Ein lokaler Portforward mit ssh -L reicht oft schon aus, um sicher auf interne Webinterfaces, Datenbanken oder Admin-Dienste zuzugreifen.

Meine Kurzfassung: Dienste nicht unnötig öffentlich machen, lieber gezielt tunneln. Wenn du den Befehl öfter brauchst, pack ihn in deine ~/.ssh/config. Und wenn etwas nicht funktioniert, denk zuerst daran, aus wessen Sicht 127.0.0.1 gerade gemeint ist. Das ist bei SSH Tunnels meistens die halbe Miete.

💬 Techniverse Community

Lust auf Austausch rund um Matrix, Selfhosting und andere smarte IT-Lösungen?
In der Techniverse Community triffst du Gleichgesinnte, kannst Fragen stellen oder einfach nerdigen Talk genießen.

Jetzt der Gruppe auf Matrix beitreten
~ Direkte Raumadresse: #community:techniverse.net

Für lockere Gespräche abseits der Kernthemen komm in den Talkraum
~ Direkte Raumadresse: #talk:techniverse.net

Wir freuen uns, wenn du dabei bist!

Vielen Dank fürs Teilen!