Wenn man gerne mit dem Raspberry Pi oder anderen Single-Board-Computern wie dem Banana Pi, Odroid und Co. bastelt, dann kommt man immer wieder mit SSH in Kontakt. Die für diese Mini-Rechner geeigneten Images basieren ja in der Regel auf einem Linux und bringen von daher auch meistens einen integrierten SSH-Zugang von Haus aus mit. In der „Bastelpraxis“ setzt man diese Rechner nun aber immer wieder neu auf oder zieht mal schnell den Stromstecker, um das Gerät „einfach“ mal schnell durchstarten zu lassen. Dadurch kommt jedoch auch SSH aus dem Tritt: Nach der Installation eines neuen Systems passt der gespeicherte SSH-Schlüssel oder beim plötzlichen Abziehen des Netzsteckers bleibt der SSH-Client hängen. Diese Probleme kann man Quick&Dirty lösen, allerdings gibt es auch immer einen sauberen Weg.

Beim Verbindungsaufbau via SSH speichert der SSH-Client in der Regel den öffentlichen SSH-Schlüssel des entfernten Systems zusammen mit dem Rechnernamen und der IP-Adresse in der Datei ~/.ssh/known_hosts im Homeverzeichnis des aktuellen Benutzers auf dem Client-Rechner. Dies wird unter anderem gemacht, um Man-in-the-Middle-Angriffe zu verhindern, bei denen ein Angreifer vorgibt, der Zielrechner zu sein, sodass man die Zugangsdaten abfischen kann. Nun schlägt diese Sicherheitsmaßnahme aber auch zu, wenn gar keine Bedrohung vorliegt: Etwa wenn man einen RasPi neu aufsetzt und man sich wieder per SSH einzuloggen versucht. SSH meldet dann in so einem Fall in großen Lettern WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED.

SSH nach erneuter Installation des Systems

$ grep 192.168.111.100 ~/.ssh/known_hosts
raspberrypi,192.168.111.100 ecdsa-sha2-nistp256 AAAAE2...ABBBBqf
$ ssh pi@192.168.111.100
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:6rR+0/i3KnPLds3EuGkfWiudIgu8VMpe1xq+X3I3yNM.
Please contact your system administrator.
Add correct host key in /home/toff/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/toff/.ssh/known_hosts:10
ECDSA host key for 192.168.111.100 has changed and you have requested strict checking.
Host key verification failed.

Nun könnte man die Datei ~/.ssh/known_hosts in einen Texteditor öffnen und die problematische Zeile 10 von Hand aus der Liste löschen, es gibt jedoch einen besseren Weg: Mit ssh-keygen -R IP-Adresse lässt sich der Schlüssel aus der Datei mit einem Kommando entfernen, sodass man beim nächsten Aufbau der Verbindung wieder bei „Null“ anfängt — den Schlüssel also wie beim allerersten Verbindungsaufbau zu diesem Rechner bestätigen muss. Das Ganze funktioniert auch, wenn ihr statt der IP-Adresse den Rechnernamen für den Verbindungsaufbau nutzt. Zur Sicherheit kopiert das Kommando den alten Stand nach ~/.ssh/known_hosts.old im selben Verzeichnis.

$ ssh-keygen -R 192.168.111.100
# Host 192.168.111.100 found: line 10
/home/toff/.ssh/known_hosts updated.
Original contents retained as /home/toff/.ssh/known_hosts.old
$ ssh pi@192.168.111.100
The authenticity of host 'raspberrypi (192.168.111.100)' can't be established.
ECDSA key fingerprint is SHA256:6rR+0/i3KnPLds3EuGkfWiudIgu8VMpe1xq+X3I3yNM.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.111.100' (ECDSA) to the list of known hosts.
pi@192.168.111.100's password: 

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Apr 22 08:40:10 2016 from 192.168.178.57

SSH-Verbindung gewaltsam trennen

Ist man auf einem entfernten Rechner per SSH eingeloggt und fährt diesen per shutdown, halt oder reboot herunter, dann beendet das System die SSH-Verbindung nicht gewaltsam. Das System beendet den SSH-Server während des Herunterfahrens sauber, sodass man wieder im Terminal des Clients-Rechners landet und dort mit demselben Terminalfenster weiterarbeiten kann. Nun stecke ich — und mit Sicherheit auch andere RasPi-Bastler — ganz gerne den Raspberry Pi vom Strom ab und wieder an, um den Rechner kurz und schmerzlos neu zu starten. Dieses Verfahren ist mit Sicherheit nicht ideal für die Integrität der Daten auf der Speicherkarte, aber wenn ich das System auf dieser sowieso neu aufsetzen möchte, kümmert mich diese wenig.

SSH-Verbindungen lassen sich mit einer Reihe von Steuercodes managen.
SSH-Verbindungen lassen sich mit einer Reihe von Steuercodes managen.

Der Nachteil ist nun aber, dass bei diesem Vorgang in der Regel auch SSH im Terminal hängen bleibt — schließlich hat man sich gerade den Stuhl unter dem Hintern weggezogen. Nun könnte man den SSH-Prozess abschließen oder das Terminal-Fenster schließen und wieder neu öffnen, doch auch für diese Situation gibt es eine saubere Lösung: SSH kennt eine Reihe von Steuerkommandos, mit denen sich die aktuelle SSH-Sitzung managen lässt. Ihr bekommt eine Übersicht über die zur Verfügung stehenden Kommandos, wenn ihr ~? (also [AltGr]+[+] und [Umschalt]+[ß]) in eine neue Zeile des Terminals eingebt — Man ein Linux-Einsteiger mag [AltGr] verwirren: Mit dieser ist die rechte Alt-Taste neben der Leertaste gemeint. Zur Sicherheit drückt ihr vorher daher einfach einmal auf die Eingabetaste.

pi@raspberrypi:~ # ~?
Supported escape sequences:
 ~.   - terminate connection (and any multiplexed sessions)
 ~B   - send a BREAK to the remote system
 ~C   - open a command line
 ~R   - request rekey
 ~V/v - decrease/increase verbosity (LogLevel)
 ~^Z  - suspend ssh
 ~#   - list forwarded connections
 ~&   - background ssh (when waiting for connections to terminate)
 ~?   - this message
 ~~   - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)

Die von der Hilfe anzeigte erste Sequenz ist bereits die gesuchte Funktion: Gebt ihr während einer SSH-Sitzung als Text ~. ein, drückt also die Tasten [AltGr]+[+] und danach [.], dann beendet ihr die aktuelle SSH-Verbindung ohne Rücksicht auf Verluste. Dies funktioniert eben nicht nur bei einer noch aktiven und weiterhin funktionierenden SSH-Sitzung (die hier ja auch mit exit jederzeit schließen könntet), sondern auch dann, wenn ihr beispielsweise den RasPi vom Strom nehmt und sich im Terminal nichts mehr tut. Auch hier kann es hilfreich sein, vor dem eigentlich Kommando noch einmal zur Sicherheit die Eingabetaste zu drücken. Sonst läuft das Steuerkommando eventuell ins Leere.

SSH-Verbindung pausieren und fortsetzen

Mit den Steuercodes lassen sich jedoch auch andere praktische Dinge machen. So könnt ihr beispielsweise eine SSH-Verbindung unterbrechen und später wieder fortsetzen, ohne dass ihr einen Terminalmultiplexer wie screen oder tmux einsetzen müsst. Braucht ein Prozess mehr Zeit als gedacht, könnt ihr die Verbindung auf diesem Weg parken, der Prozess auf dem entfernten Rechner läuft weiter. Im Gegensatz zu den beiden genannten Terminalmultiplexern müsst ihr nicht im Vorfeld daran denken, dass der Vorgang länger brauchen könnte und diese vorsorglich starten. Das entsprechende Steuerzeichen nennt sich nun etwas kryptisch ~^Z, der Zirkumflex steht dabei nicht als Zeichen, sondern als Steuerzeichen. Ihr müsst also [AltGr]+[+] und danach [Strg]+[Umschalt]+[Z] drücken. Anschließend landet ihr wieder im Terminal des Rechners, auf dem ihr ursprünglich ssh ausgeführt habt. Von dort aus könnt ihr die Verbindung wieder mit dem Aufruf von fg und [Eingabe] aufgreifen.

Eine SSH-Verbindung pausieren und wieder fortsetzen.
Eine SSH-Verbindung pausieren und wieder fortsetzen.

Arbeitet ihr auf einem „richtig“ entfernten System über das Internet, kann es durchaus passieren, dass die Verbindung abbricht. Dies liegt auf der einen Seite daran, dass der Server bei Inaktivität die Verbindung beendet, auf der anderen Seite kann es zu Situationen kommen, in denen die eigene Netzwerk-Infrastruktur (sprich der Router) dazwischenfunkt: Es gibt jedoch die Möglichkeit den Timeout mit einer Keep-Alive-Funktion zu verhindern. Je nach Situation könnt ihr entweder den SSH-Server entsprechend konfigurieren (dazu benötigt ihr natürlich Root-Rechte) oder ihr ruft die SSH-Verbindung gleich mit den entsprechenden Parameter auf. Für diesen Fall benötigt ihr keine besonderen Rechte auf beiden Systemen.

Keep-Alive serverseitig

### Keep-Alive-Standardeinstellung:
$ grep Alive /etc/ssh/sshd_config
#TCPKeepAlive yes
#ClientAliveInterval 0
#ClientAliveCountMax 3
### Die Konfiguration des SSH-Servers bearbeiten:
$ sudo nano /etc/ssh/sshd_config

### Die entsprechenden Zeilen sollte am Ende so aussehen:
$ grep Alive /etc/ssh/sshd_config
TCPKeepAlive yes
ClientAliveInterval 60
ClientAliveCountMax 3

### SSH-Server einmal neu durchstarten:
$ sudo systemctl restart sshd

Keep-Alive clientseitig

### SSH-Verbindung clientseitig am Leben halten
$ ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=1 pi@raspberrypi

Im ersten Fall gilt die Einstellung für alle User, die sich per SSH auf dem System einloggen möchten. In der Regel sollte man diese Konfiguration daher nur dann vornehmen, wenn auch alle User tatsächlich diese benötigen. Meistens braucht man das Keep-Alive allerdings nur im Ausnahmefall, von daher ist es sinnvoll die Option nur bei Bedarf mit dem Aufruf von ssh zu setzen. Bei mir ist das beispielsweise bei einem Web-Service der Fall, bei dem ich mich per SSH einloggen kann. Stoße ich dann dort längere Zeit laufende Backups an, dann beendet mein Router die Verbindung bevor der Backupprozess erfolgreich den Vollzug melden kann. Mit den genannten Keep-Alive-Settings beim Aufruf ist das jedoch kein Problem mehr.

6 Kommentare

  1. Sehr interessanter Artikel. Besonders die Steuerkommandos kannte ich noch gar nicht, hatte aber auch bereits oft das Problem einer aufgehangenen Sitzung.

    Noch ein Hinweis: Anfangs schreibst du immer [AltGR]+[#] als Tastenkombination für die Tilde. Richtig wäre aber [AltGR]+[+], so wie du es bei der letzten Verwendung ( ~^Z) auch schreibst.

  2. Könntest Du die Anpassungen für die Keep-Alive-Einstellung nicht auch in die $HOME/.ssh/config schreiben? Dann gelten sie weder für alle Nutzer noch musst Du sie jedes Mal aufs neue mit SSH aufrufen.

    Nur so eine Idee.

  3. Über die Steuerkommandos kann man übrigens auch eine SSH-Konsole öffnen in der man bei einer laufenden Verbindung Port-Weiterleitungen erstellen kann. Das geht auch über mehrere verschachtelte connections hinweg.

    Ansonsten umgehe ich diesen ganzen keepalive klimbim einfach durch Nutzung von Mosh. Das läuft immer. Ethernet-Kabel gezogen oder WLAN-Verbindung weg? Kein Problem. Sobald die Verbindung wieder da ist, klappt es wieder.

  4. Das mit der ssh Konsole kannte ich noch nicht. Aber ich verwende immer die Option -o UserKnownHostsFile=/dev/null. Das spart das nachträgliche Herauslöschen.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein