SSH-Tunneling unter Linux erzeugt verschlüsselte Kanäle, über die Netzwerkverkehr zwischen Rechnern weitergeleitet wird. So lassen sich Dienste hinter Firewalls erreichen, ungeschützte Protokolle absichern und sichere Verbindungswege durch nicht vertrauenswürdige Netzwerke aufbauen. Egal ob man eine Datenbank in einem privaten Netzwerk erreichen, einen lokalen Entwicklungsserver einem Kollegen zugänglich machen oder den Browserverkehr über einen vertrauenswürdigen Ausgangspunkt leiten möchte — SSH-Port-Forwarding erledigt all das mit Werkzeugen, die auf jedem Linux-System bereits vorhanden sind. Dieser Leitfaden behandelt alle drei Weiterleitungsarten mit praxiserprobten Konfigurationen.
Voraussetzungen
- Zwei Linux-Rechner mit SSH-Zugang (oder ein Linux-Client und ein beliebiger SSH-Server)
- OpenSSH-Client lokal installiert (
ssh -Vzur Überprüfung) - OpenSSH-Server auf dem Remote-Rechner aktiv (
sshd) - Grundlegendes Verständnis von TCP-Ports und Client-Server-Netzwerken
- SSH-Schlüsselauthentifizierung eingerichtet (empfohlen — siehe verwandter Artikel)
Die drei SSH-Tunnel-Typen
SSH unterstützt drei verschiedene Weiterleitungsmodi, die jeweils für unterschiedliche Anwendungsfälle gedacht sind:
| Typ | Flag | Richtung | Einsatzgebiet |
|---|---|---|---|
| Lokale Weiterleitung | -L | Lokaler Rechner → Remote-Ziel | Zugriff auf Remote-Datenbank, Web-UI oder Dienst |
| Remote-Weiterleitung | -R | Remote-Server → lokaler Rechner | Lokalen Dev-Server freigeben, Remote-Zugriff auf lokale Dienste |
| Dynamische Weiterleitung | -D | Lokaler SOCKS-Proxy → beliebiges Ziel über Remote | Sicheres Surfen, gesamten Verkehr über SSH leiten |
Alle drei verschlüsseln den Datenverkehr Ende-zu-Ende zwischen SSH-Client und SSH-Server. Der Verkehr zwischen SSH-Server und Endziel wird von SSH nicht verschlüsselt — er läuft über das lokale Netzwerk des Servers.
Lokale Port-Weiterleitung (-L)
Die lokale Weiterleitung ist der häufigste Typ. Sie bindet einen Port auf dem lokalen Rechner und schickt den Datenverkehr durch den SSH-Tunnel an ein bestimmtes Ziel, das vom Remote-Server aus erreichbar ist.
Syntax
ssh -L [bind_address:]local_port:destination:dest_port user@ssh_server
Beispiel: Zugriff auf eine Remote-Datenbank
Eine PostgreSQL-Datenbank auf db.internal Port 5432 ist nur vom Anwendungsserver app.example.com aus erreichbar. Der eigene Laptop hat keinen direkten Zugriff auf db.internal.
# Lokalen Port 5432 zu db.internal:5432 über app.example.com weiterleiten
ssh -L 5432:db.internal:5432 admin@app.example.com
Jetzt lokal zur Datenbank verbinden:
psql -h localhost -p 5432 -U myuser mydb
Datenpfad: Laptop:5432 → SSH-Tunnel → app.example.com → db.internal:5432
Beispiel: Zugriff auf ein Remote-Web-Interface
Ein Monitoring-Dashboard läuft auf http://monitor.internal:3000 hinter einer Firewall:
# Lokalen Port 8080 zum Remote-Dashboard weiterleiten
ssh -L 8080:monitor.internal:3000 admin@jumpbox.example.com
# Im Browser öffnen
# http://localhost:8080
Tunnel im Hintergrund (ohne Shell)
Mit -f -N läuft der Tunnel im Hintergrund, ohne eine Remote-Shell zu öffnen:
# -f = nach Authentifizierung in den Hintergrund
# -N = kein Remote-Befehl (nur Tunnel)
ssh -f -N -L 8080:monitor.internal:3000 admin@jumpbox.example.com
Einen Hintergrundtunnel beendet man so:
ps aux | grep 'ssh -f -N -L'
kill <PID>
An alle Interfaces binden
Standardmäßig bindet -L nur an localhost. Damit andere Rechner im Netzwerk den Tunnel nutzen können:
# An alle Interfaces binden (0.0.0.0)
ssh -L 0.0.0.0:8080:monitor.internal:3000 admin@jumpbox.example.com
# Oder an ein bestimmtes Interface binden
ssh -L 192.168.1.100:8080:monitor.internal:3000 admin@jumpbox.example.com
Sicherheitshinweis: Das Binden an 0.0.0.0 macht den Tunnel im gesamten lokalen Netzwerk zugänglich. Dies sollte nur in vertrauenswürdigen Netzwerken erfolgen.
Remote-Port-Weiterleitung (-R)
Die Remote-Weiterleitung funktioniert in die entgegengesetzte Richtung — sie bindet einen Port auf dem Remote-Server und leitet den Datenverkehr zurück zum lokalen Rechner.
Syntax
ssh -R [bind_address:]remote_port:destination:dest_port user@ssh_server
Beispiel: Lokalen Entwicklungsserver freigeben
Man entwickelt eine Webanwendung auf localhost:3000 und möchte, dass ein Kollege auf dem Remote-Server darauf zugreifen kann:
# Port 9000 auf dem Remote-Server binden, Weiterleitung zum lokalen Port 3000
ssh -R 9000:localhost:3000 admin@remote.example.com
Jetzt kann jeder auf remote.example.com den lokalen Dev-Server unter http://localhost:9000 erreichen.
Beispiel: Remote-Zugriff auf einen lokalen Dienst ermöglichen
Der Büro-Rechner betreibt einen Dienst auf Port 8443 und man möchte von zu Hause über einen Cloud-Server darauf zugreifen:
# Vom Büro-Rechner aus:
ssh -R 8443:localhost:8443 user@cloud-server.example.com
Von zu Hause in den Cloud-Server einloggen und localhost:8443 aufrufen.
Externe Verbindungen zulassen
Standardmäßig binden remote weitergeleitete Ports auf dem Remote-Server an localhost. Für externen Zugriff muss GatewayPorts auf dem SSH-Server aktiviert werden:
# Auf dem SSH-Server in /etc/ssh/sshd_config:
GatewayPorts yes # Bindung an alle Interfaces erlauben
# oder
GatewayPorts clientspecified # Client entscheidet die Bind-Adresse
Dann sshd neu starten und die Bind-Adresse angeben:
ssh -R 0.0.0.0:9000:localhost:3000 admin@remote.example.com
Dynamische Port-Weiterleitung (-D) — SOCKS-Proxy
Die dynamische Weiterleitung erstellt einen lokalen SOCKS5-Proxy. Jede Anwendung, die diesen Proxy verwendet, leitet ihren gesamten Datenverkehr durch den SSH-Tunnel, wobei der Remote-Server als Ausgangspunkt dient.
Syntax
ssh -D [bind_address:]port user@ssh_server
Beispiel: Sicheres Surfen
Man befindet sich in einem nicht vertrauenswürdigen WLAN und möchte den gesamten Browserverkehr über den Heimserver leiten:
# SOCKS5-Proxy auf lokalem Port 1080 erstellen
ssh -D 1080 -f -N user@home-server.example.com
Dann den Browser konfigurieren:
- Firefox: Einstellungen → Netzwerk-Einstellungen → Manuelle Proxy-Konfiguration → SOCKS-Host:
localhost, Port:1080, SOCKS v5. Option “DNS über SOCKS v5-Proxy” aktivieren. - Chrome (Kommandozeile):
google-chrome --proxy-server="socks5://localhost:1080" - Systemweit (Umgebungsvariable):
export ALL_PROXY=socks5://localhost:1080
Beispiel: CLI-Tools über den Proxy leiten
# Mit curl verwenden
curl --proxy socks5h://localhost:1080 https://ifconfig.me
# Mit git verwenden
git -c http.proxy=socks5h://localhost:1080 clone https://github.com/user/repo.git
# Das 'h' in socks5h bedeutet: DNS-Auflösung erfolgt auf der Remote-Seite
Wichtig: socks5h:// (mit dem h) verwenden, damit die DNS-Auflösung über den Proxy erfolgt. Reines socks5:// löst DNS lokal auf, was DNS-Anfragen im lokalen Netzwerk preisgibt.
Tunnel dauerhaft betreiben mit autossh
SSH-Tunnel brechen ab, wenn die Verbindung unterbrochen wird (Netzwerkausfall, Laptop-Ruhezustand, Server-Neustart). autossh überwacht die Verbindung und baut sie automatisch wieder auf.
Installation
# Debian / Ubuntu
sudo apt install autossh
# RHEL / Fedora
sudo dnf install autossh
# Arch Linux
sudo pacman -S autossh
Verwendung
# Dauerhafter lokaler Tunnel mit autossh
autossh -M 0 -f -N -L 5432:db.internal:5432 admin@jumpbox.example.com
# Dauerhafter SOCKS-Proxy
autossh -M 0 -f -N -D 1080 user@home-server.example.com
# Dauerhafter Remote-Tunnel
autossh -M 0 -f -N -R 9000:localhost:3000 admin@remote.example.com
Das Flag -M 0 deaktiviert autossh’s eigenen Überwachungsport und verlässt sich stattdessen auf SSH’s eigenen Keepalive-Mechanismus — zuverlässiger und einfacher. Am besten mit SSH-Keepalives in der Konfiguration kombinieren.
Als systemd-Dienst betreiben
Für Tunnel, die Neustarts überstehen müssen, eine systemd-Unit anlegen:
# /etc/systemd/system/ssh-tunnel-db.service
[Unit]
Description=SSH Tunnel to Database
After=network-online.target
Wants=network-online.target
[Service]
User=tunneluser
ExecStart=/usr/bin/autossh -M 0 -N -L 5432:db.internal:5432 admin@jumpbox.example.com
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now ssh-tunnel-db.service
sudo systemctl status ssh-tunnel-db.service
SSH-Konfiguration für wiederverwendbare Tunnel
Statt langer Befehle Tunnel in ~/.ssh/config definieren:
Host db-tunnel
HostName jumpbox.example.com
User admin
LocalForward 5432 db.internal:5432
ServerAliveInterval 60
ServerAliveCountMax 3
IdentityFile ~/.ssh/id_ed25519
Host socks-proxy
HostName home-server.example.com
User myuser
DynamicForward 1080
ServerAliveInterval 60
ServerAliveCountMax 3
IdentityFile ~/.ssh/id_ed25519
Host expose-dev
HostName remote.example.com
User admin
RemoteForward 9000 localhost:3000
ServerAliveInterval 60
ServerAliveCountMax 3
Jetzt per Name verwenden:
ssh -f -N db-tunnel
ssh -f -N socks-proxy
ssh -f -N expose-dev
SSH-Tunneling im Vergleich mit Alternativen
| Merkmal | SSH-Tunneling | WireGuard VPN | Cloudflare Tunnel | ngrok |
|---|---|---|---|---|
| Verschlüsselung | Ja (SSH) | Ja (WireGuard) | Ja (TLS) | Ja (TLS) |
| Benötigt Server-Software | sshd (überall vorhanden) | WireGuard-Kernelmodul | cloudflared-Daemon | ngrok-Agent |
| Port-genaue Weiterleitung | Ja | Nein (ganzes Netzwerk) | Ja | Ja |
| SOCKS-Proxy | Ja (-D) | Nein | Nein | Nein |
| Geschwindigkeits-Overhead | Moderat (TCP-over-TCP) | Gering (UDP, Kernel-Space) | Gering | Gering |
| Automatische Wiederverbindung | Mit autossh | Eingebaut | Eingebaut | Eingebaut |
| Kosten | Kostenlos | Kostenlos | Kostenloser Tarif verfügbar | Kostenloser Tarif verfügbar |
| Am besten für | Schnelle Ad-hoc-Tunnel, Zugriff auf bestimmte Ports | Site-to-Site oder vollständiger Netzwerkzugang | Dienste im Internet veröffentlichen | Schnelle Demos, Webhooks |
SSH-Tunneling verwenden, wenn man schnell auf einen oder zwei bestimmte Ports zugreifen muss und bereits SSH-Zugang hat — keine zusätzliche Software nötig. Zu WireGuard wechseln, wenn vollständiger Netzwerkzugang oder hoher Durchsatz benötigt wird. Cloudflare Tunnels oder ngrok einsetzen, wenn Dienste mit öffentlichen URLs für externe Nutzer bereitgestellt werden sollen.
Fehlerbehebung bei SSH-Tunneln
Tunnel verbindet sich, aber kein Datenverkehr fließt
# Prüfen, ob der Tunnel lauscht
ss -tlnp | grep <local_port>
# Prüfen, ob das Ziel vom SSH-Server aus erreichbar ist
ssh admin@jumpbox.example.com "nc -zv db.internal 5432"
Wenn ss den Port als lauschend anzeigt, Verbindungen aber hängen, lehnt der Zieldienst möglicherweise Verbindungen von der IP des SSH-Servers ab. Firewall-Regeln auf dem Zielhost prüfen.
”bind: Address already in use"
# Herausfinden, was den Port belegt
sudo ss -tlnp | grep <port>
# Alten Tunnel beenden oder anderen lokalen Port wählen
ssh -L 15432:db.internal:5432 admin@jumpbox.example.com
"channel 3: open failed: administratively prohibited”
TCP-Forwarding ist auf dem SSH-Server deaktiviert. Der Server-Administrator muss in /etc/ssh/sshd_config folgendes eintragen:
AllowTcpForwarding yes
# oder nur für lokale Weiterleitung:
AllowTcpForwarding local
Tunnel trennt sich nach Inaktivitätsperiode
Keepalives in ~/.ssh/config eintragen:
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
Damit wird alle 60 Sekunden ein Keepalive gesendet und nach 3 ausgebliebenen Antworten (3 Minuten) getrennt. NAT-Geräte und Stateful-Firewalls schließen die inaktive TCP-Verbindung so nicht mehr.
Remote-weitergeleiteter Port von außen nicht erreichbar
Prüfen, ob GatewayPorts auf dem SSH-Server aktiviert ist:
grep GatewayPorts /etc/ssh/sshd_config
Wenn der Wert no ist oder die Zeile fehlt, binden remote weitergeleitete Ports auf dem Server nur an 127.0.0.1.
Sicherheitsüberlegungen
-
Weiterleitung in authorized_keys einschränken: Was ein bestimmter Schlüssel darf, lässt sich begrenzen:
no-agent-forwarding,no-X11-forwarding,permitopen="db.internal:5432" ssh-ed25519 AAAA...Dieser Schlüssel kann nur Tunnel zu
db.internal:5432erstellen. -
Weiterleitung für bestimmte Benutzer deaktivieren: In
/etc/ssh/sshd_config:Match User restricteduser AllowTcpForwarding no -
TCP-over-TCP-Performance: SSH-Tunnel leiden unter dem TCP-over-TCP-Problem — der innere und der äußere TCP-Stack behandeln Neuübertragungen jeweils eigenständig, was bei verlustbehafteten Verbindungen zu exponentiellem Backoff führen kann. Für hohen Durchsatz oder latenzkritischen Verkehr besser WireGuard verwenden.
-
Tunnel-Nutzung überwachen: Aktive Tunnel auf Servern kontrollieren:
# Alle aktiven SSH-Port-Weiterleitungen anzeigen sudo ss -tlnp | grep sshd # Verbundene SSH-Sitzungen mit Weiterleitung anzeigen sudo lsof -i -n | grep ssh | grep LISTEN
Zusammenfassung
- Lokale Weiterleitung (
-L) bringt Remote-Dienste auf den lokalen Rechner — der häufigste Anwendungsfall für den Zugriff auf Datenbanken, Dashboards und APIs hinter Firewalls - Remote-Weiterleitung (
-R) stellt lokale Dienste auf einem Remote-Server bereit — nützlich für das Teilen von Entwicklungsumgebungen und den externen Zugriff auf interne Tools - Dynamische Weiterleitung (
-D) erstellt einen SOCKS5-Proxy — leitet den Datenverkehr beliebiger Anwendungen durch den SSH-Tunnel für sicheres Surfen in nicht vertrauenswürdigen Netzwerken autosshverwenden für dauerhafte Tunnel, die Netzwerkunterbrechungen überstehen, und systemd-Dienste für Tunnel, die auch Neustarts überdauern- SSH-Konfigurationsdateien (
~/.ssh/config) ersparen wiederholte Kommandozeilenflags und machen Tunnel unter einfachen Namen wiederverwendbar - Keepalives einrichten (
ServerAliveInterval 60), damit Firewalls inaktive Tunnelverbindungen nicht trennen