Jeden Tunnel in ~/.ssh/config speichern
Wer die Optionen -L und -R jedes Mal neu tippt, verwechselt früher oder später die Ports. Geben Sie stattdessen jedem Tunnel einen Namen, als eigenen Host-Block:
Host db-tunnel
HostName 203.0.113.10
User deploy
LocalForward 127.0.0.1:5432 127.0.0.1:5432
ExitOnForwardFailure yes
Host dev-share
HostName 203.0.113.10
User deploy
RemoteForward 127.0.0.1:9000 127.0.0.1:3000
Host socks
HostName 203.0.113.10
User deploy
DynamicForward 127.0.0.1:1080
Jede Zeile ist die Konfigurationsform einer Kommandozeilenoption: LocalForward entspricht -L, RemoteForward entspricht -R und DynamicForward entspricht -D. Zuerst kommen Listen-Adresse und Port, dann ein Leerzeichen, dann das Ziel. Wie bei den Optionen löst der Server das Ziel einer lokalen Weiterleitung auf, 127.0.0.1 meint dort also den Server selbst. Wenn Ihnen die drei Arten neu sind, beginnen Sie mit SSH-Tunnel erklärt: local, remote und dynamic.
Verwenden Sie für Tunnel einen eigenen Namen, nicht den Host, mit dem Sie sich täglich anmelden. Sonst versucht jede Anmeldung, dieselben Ports zu öffnen, und die zweite meldet Address already in use.
Einen Tunnel über seinen Namen starten
ssh -f -N db-tunnel
-N führt keinen Befehl auf dem Server aus, die Verbindung trägt also nur die Weiterleitungen. -f schickt ssh nach der Anmeldung in den Hintergrund, eine Abfrage von Passphrase oder Passwort erreicht Sie also trotzdem zuerst. Ihr Datenbank-Tool kann sich jetzt mit 127.0.0.1:5432 verbinden.
Mit ExitOnForwardFailure yes beendet ein bereits belegter Port ssh mit Exit-Code 255, statt eine Verbindung ohne Tunnel stehen zu lassen. So sieht es aus, wenn Sie denselben Tunnel zweimal starten:
bind [127.0.0.1]:5432: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 5432
Could not request local forwarding.
Mehrere gespeicherte Tunnel auf einmal starten:
for t in db-tunnel socks; do ssh -f -N "$t"; done
Einen Tunnel beenden
Ein Tunnel im Hintergrund ist nur ein ssh-Prozess. Ohne weitere Hilfsmittel suchen Sie ihn und beenden ihn:
ps ax | grep '[s]sh -f -N db-tunnel'
pkill -f 'ssh -f -N db-tunnel'
pkill -f trifft jeden Prozess, dessen Befehlszeile diesen Text enthält. In unseren Tests hat es auch das Shell-Skript beendet, das den Tunnel gestartet hatte, weil das Skript dieselben Wörter enthielt. Ein Control-Socket ist sauberer. Ergänzen Sie den Block um drei Zeilen:
Host db-tunnel
HostName 203.0.113.10
User deploy
LocalForward 127.0.0.1:5432 127.0.0.1:5432
ExitOnForwardFailure yes
ControlMaster auto
ControlPath ~/.ssh/cm-%C
ControlPersist yes
Jetzt reagiert der Tunnel auf Befehle mit seinem Namen:
ssh -f -N db-tunnel
ssh -O check db-tunnel
ssh -O exit db-tunnel
Master running (pid=27)
Exit request sent.
Über den Socket können auch andere ssh- und scp-Befehle an db-tunnel dieselbe Verbindung nutzen. Details stehen in SSH-Multiplexing mit ControlMaster.
Weiterleitungen ohne neue Verbindung hinzufügen oder entfernen
Mit einem Control-Socket können Sie einen laufenden Tunnel ändern. Die Verbindung und ihre anderen Weiterleitungen bleiben bestehen:
ssh -O forward -L 127.0.0.1:8081:127.0.0.1:8000 db-tunnel
ssh -O cancel -L 127.0.0.1:8081:127.0.0.1:8000 db-tunnel
cancel braucht genau dieselbe Angabe, mit der Sie die Weiterleitung hinzugefügt haben. Das funktioniert auch für -R und -D. Mit -R 0:... wählt der Server einen freien Port, und ssh -O forward gibt ihn aus.
Einen gespeicherten Tunnel am Laufen halten
Ein mit -f gestarteter Tunnel lebt so lange wie seine SSH-Verbindung. Ruhezustand, ein WLAN-Wechsel oder ein Neustart des Servers beenden ihn. Ergänzen Sie den Block um diese Zeilen, damit ssh eine tote Verbindung nach etwa 45 Sekunden erkennt und sich beendet, statt zu hängen:
ServerAliveInterval 15
ServerAliveCountMax 3
Danach muss ihn etwas neu starten: eine Schleife, ein Dienstverwalter oder autossh für einen dauerhaften SSH-Tunnel.
Fehler, die gespeicherte Tunnel kaputt machen
- Doppelpunkt statt Leerzeichen.
LocalForward 5432:127.0.0.1:5432ist das Format der Kommandozeile, nicht das der Konfiguration. ssh meldetMissing target argument, und in unserem Test hat diese eine falsche Zeile die Verbindung zu allen Hosts der Datei verhindert. - Lauschen auf allen Schnittstellen.
LocalForward 0.0.0.0:5432 ...oderGatewayPorts yeslassen andere Rechner in Ihrem Netzwerk den Tunnel nutzen. Bleiben Sie bei127.0.0.1, wenn Sie das nicht ausdrücklich wollen. - Zwei Tunnel auf demselben lokalen Port. Nur der erste startet. Geben Sie jedem gespeicherten Tunnel einen eigenen Port.
- Weiterleitung vom Server abgelehnt. Öffnet sich der Port, scheitern Verbindungen aber mit
administratively prohibited, hat der ServerAllowTcpForwardingfür Sie abgeschaltet.
Fragen
Wie sehe ich, welche SSH-Tunnel laufen?
Führen Sie ps ax | grep '[s]sh -f -N' aus, um ssh-Prozesse im Hintergrund mit ihren Optionen aufzulisten. Bei einem Tunnel mit Control-Socket antwortet ssh -O check name direkt. In einer interaktiven Sitzung drücken Sie Enter und tippen ~#, um die weitergeleiteten Verbindungen zu sehen.
Kann ein Befehl mehrere Tunnel starten?
Ja. Schreiben Sie mehrere LocalForward- oder DynamicForward-Zeilen in einen Host-Block, dann öffnen sich alle mit einem einzigen ssh -f -N name. Ist ein Port belegt und ExitOnForwardFailure aktiv, bleibt keiner offen.
Warum stoppt mein gespeicherter Tunnel nach dem Ruhezustand oder einem Netzwechsel?
Der Tunnel lebt in einer einzigen SSH-Verbindung, und die bricht ab, wenn das Netz weg ist. Setzen Sie ServerAliveInterval, damit ssh das bemerkt, und starten Sie ihn mit einer Schleife oder mit autossh neu.
Quellen
- ssh(1), -f, -N und -O, OpenBSD-Handbuch
- ssh_config(5), LocalForward, RemoteForward, DynamicForward, ControlMaster
- sshd_config(5), AllowTcpForwarding und GatewayPorts