SSH ist für die meisten Entwickler gleichbedeutend mit ssh user@host — eine Remote Shell öffnen, Befehle ausführen, fertig. Das ist ungefähr so, als würde man einen Schweizer Taschenmesser ausschließlich zum Flaschenöffnen benutzen. Die eigentliche Stärke von SSH liegt in seinen Tunnel-Fähigkeiten: Port Forwarding, dynamische Proxies und Jump Hosts. Werkzeuge, die Netzwerkprobleme lösen, für die viele reflexartig nach einem VPN greifen.
Warum SSH-Tunnel statt VPN?
Ein VPN verbindet ganze Netzwerke. Das ist maechtig, aber auch aufwändig: Konfiguration, Zertifikate, Client-Software, Routing-Tabellen. Fuer viele Alltagsprobleme ist das wie mit Kanonen auf Spatzen schiessen.
SSH-Tunnel sind chirurgisch präzise. Ein einzelner Port, eine einzelne Verbindung, sofort verfügbar auf jedem System mit OpenSSH. Kein Setup, keine zusätzliche Software, keine Adminrechte nötig.
Local Port Forwarding (-L)
Das häufigste Szenario: Ein Dienst läuft in einem Remote-Netzwerk und ist nicht direkt erreichbar — eine Datenbank hinter einer Firewall, ein internes Monitoring-Dashboard, eine API im Staging-Netz.
Local Forwarding bindet einen lokalen Port an einen entfernten Dienst. Alles, was auf dem lokalen Port ankommt, wird durch den SSH-Tunnel zum Ziel geleitet.
# Syntax: ssh -L [local_bind:]local_port:remote_host:remote_port user@ssh_server
# PostgreSQL hinter Firewall lokal auf Port 5433 verfügbar machen
ssh -L 5433:db-intern.example.com:5432 deploy@bastion.example.com
# Jetzt verbinden: psql -h localhost -p 5433 -U app mydb
# Internes Grafana-Dashboard lokal öffnen
ssh -L 3000:monitoring.internal:3000 deploy@bastion.example.com
# Browser: http://localhost:3000 Der entscheidende Punkt: remote_host wird aus Sicht des SSH-Servers aufgeloest. db-intern.example.com muss nicht von deinem Rechner erreichbar sein — nur vom Bastion Host.
Remote Port Forwarding (-R)
Remote Forwarding funktioniert in die umgekehrte Richtung: Ein lokaler Dienst wird über den SSH-Server erreichbar gemacht. Zwei typische Anwendungsfaelle:
- Webhook-Entwicklung: Ein Payment-Provider muss deinen lokalen Dev-Server erreichen
- Demo für Kunden: Eine lokal laufende App kurzzeitig extern zugänglich machen
# Syntax: ssh -R [remote_bind:]remote_port:local_host:local_port user@ssh_server
# Lokalen Dev-Server (Port 3000) auf dem Remote-Server unter Port 8080 verfügbar machen
ssh -R 8080:localhost:3000 deploy@public-server.example.com
# Jetzt erreichbar: http://public-server.example.com:8080
# Nur auf localhost des Remote-Servers binden (sicherer)
ssh -R 127.0.0.1:8080:localhost:3000 deploy@public-server.example.com Dynamic Port Forwarding (-D)
Dynamic Forwarding erstellt einen lokalen SOCKS5-Proxy. Statt einen einzelnen Port weiterzuleiten, kannst du beliebigen Traffic durch den SSH-Tunnel routen. Das ist besonders nuetzlich, wenn du im Browser durch ein Remote-Netzwerk navigieren musst — zum Beispiel interne Webanwendungen erreichen, die nur aus dem Firmennetz zugänglich sind.
# Syntax: ssh -D [bind_address:]port user@ssh_server
# SOCKS5-Proxy auf Port 1080 starten
ssh -D 1080 deploy@office-gateway.example.com
# Firefox: Einstellungen > Netzwerk > SOCKS Host: localhost, Port: 1080
# Oder per CLI:
curl --socks5 localhost:1080 http://intranet.corp.local/api/status
# Mit nötig: DNS-Anfragen auch durch den Tunnel leiten
ssh -D 1080 -o "ProxyCommand=none" deploy@office-gateway.example.com Der Vorteil gegenueber Local Forwarding: Du musst nicht im Voraus wissen, welche Hosts und Ports du brauchst. Der gesamte Traffic, den du durch den Proxy leitest, wird im Remote-Netzwerk aufgeloest.
Jump Hosts / ProxyJump (-J)
In professionellen Umgebungen erreichst du Zielserver selten direkt. Der Weg fuehrt über einen oder mehrere Bastion Hosts. Frueher hat man das mit verschachtelten SSH-Sessions oder ProxyCommand geloest — umstaendlich und fehleranfaellig.
Seit OpenSSH 7.3 gibt es -J (ProxyJump), und es ist elegant:
# Syntax: ssh -J jump_host1,jump_host2 target_host
# Durch einen Bastion Host zum Zielserver
ssh -J bastion.example.com webserver.internal
# Durch zwei Hops
ssh -J bastion.example.com,dmz-gateway.internal db-server.private
# Kombination mit Port Forwarding
ssh -J bastion.example.com -L 5432:localhost:5432 db-server.internal Jeder Hop in der Kette nutzt SSH, sodass die gesamte Verbindung verschluesselt ist. Der Bastion Host sieht nur verschluesselten Traffic — er kann nicht mitlesen, was zwischen dir und dem Zielserver passiert.
SSH Config: Tunnel dauerhaft einrichten
Jedes Mal lange Kommandozeilen tippen ist keine Lösung für den Alltag. Die ~/.ssh/config macht Tunnel persistent und wiederverwendbar.
# Bastion Host als Jump Server definieren
Host bastion
HostName bastion.example.com
User deploy
IdentityFile ~/.ssh/id_ed25519_work
# Interner DB-Server via Bastion
Host db-staging
HostName db-staging.internal
User deploy
ProxyJump bastion
LocalForward 5433 localhost:5432
# Internes Monitoring via Bastion
Host monitoring
HostName monitoring.internal
User deploy
ProxyJump bastion
LocalForward 3000 localhost:3000
LocalForward 9090 localhost:9090
# SOCKS-Proxy ins Firmennetz
Host office-proxy
HostName office-gateway.example.com
User deploy
DynamicForward 1080
# Globale Defaults
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yes Danach reicht ein ssh db-staging — der Tunnel steht, die Datenbank ist auf localhost:5433 erreichbar. Kein Nachdenken, kein Nachschlagen.
Autossh: Tunnel die sich selbst heilen
SSH-Tunnel brechen ab. Netzwerkwechsel, instabiles WLAN, ein Neustart des Servers — die Verbindung ist weg und der Tunnel tot. autossh überwacht die Verbindung und baut sie automatisch wieder auf.
# Installation
sudo apt install autossh # Debian/Ubuntu
brew install autossh # macOS
# Autossh mit Monitoring-Port
autossh -M 20000 -f -N -L 5433:db:5432 deploy@bastion.example.com
# -M 20000 : Monitoring-Port (autossh prueft die Verbindung)
# -f : In den Hintergrund
# -N : Keine Remote-Shell öffnen (nur Tunnel)
# Ohne Monitoring-Port (nutzt ServerAliveInterval)
autossh -M 0 -f -N \
-o "ServerAliveInterval=30" \
-o "ServerAliveCountMax=3" \
-L 5433:db:5432 deploy@bastion.example.com
# Als systemd-Service für permanente Tunnel
# /etc/systemd/system/ssh-tunnel-db.service
# [Unit]
# Description=SSH Tunnel to Staging DB
# After=network-online.target
#
# [Service]
# User=deploy
# ExecStart=/usr/bin/autossh -M 0 -N -o "ServerAliveInterval=30" \
# -o "ServerAliveCountMax=3" -L 5433:db:5432 deploy@bastion
# Restart=always
# RestartSec=10
#
# [Install]
# WantedBy=multi-user.target Die Kombination aus autossh und systemd ergibt Tunnel, die Neustarts und Netzwerkausfaelle ueberleben — zuverlässig genug für produktionsnahe Setups.
Sicherheit: Was du beachten musst
SSH-Tunnel sind maechtig, und Macht erfordert Verantwortung. Ein paar Punkte, die in der Praxis oft uebersehen werden:
Key-Only Authentication: Passwort-Authentifizierung hat auf Servern nichts zu suchen. Ed25519-Keys sind der aktuelle Standard — klein, schnell, sicher.
Bind-Adressen kontrollieren: Standardmaessig binden Local Forwards an localhost. Wer -L 0.0.0.0:5433:db:5432 schreibt, macht die Datenbank für jeden im lokalen Netz erreichbar. Meistens nicht gewollt.
Forwarding auf dem Server einschraenken: In sshd_config kann gezielt gesteuert werden, was erlaubt ist:
AllowTcpForwarding no— kein Port Forwarding erlaubtAllowTcpForwarding local— nur Local ForwardingPermitOpen host:port— nur bestimmte Ziele erlaubbarGatewayPorts no— Remote Forwards nur auf localhost
Dedizierte Tunnel-User: Fuer automatisierte Tunnel lohnt sich ein eigener User mit eingeschraenkter Shell (/bin/false oder command= in authorized_keys). So kann der Key nur für den Tunnel genutzt werden, nicht für eine interaktive Shell.
Monitoring: Wer nicht weiß, welche Tunnel aktiv sind, hat ein Problem. ss -tlnp auf dem Server zeigt alle lauschenden Tunnel-Ports.
Fazit
SSH-Tunneling ist kein Nischenthema — es gehört in den Werkzeugkasten jedes Entwicklers, der mit Remote-Systemen arbeitet. Local Forwarding für den Zugriff auf interne Dienste, Remote Forwarding für Webhook-Entwicklung, Dynamic Forwarding als Ad-hoc-VPN, und ProxyJump für mehrstufige Infrastrukturen.
Der groesste Vorteil: SSH ist ueberall. Kein Client zu installieren, keine Firewall-Regeln zu beantragen, keine Admins zu ueberzeugen. Ein einzelner Befehl, und der Tunnel steht. Wer das einmal verinnerlicht hat, fragt sich, warum er jemals ohne gearbeitet hat.