Ściąga SSH — sekwencje ucieczki i ratowanie sesji

Zasada działania#

Sekwencje ucieczki przechwytuje lokalny klient SSH, zanim cokolwiek poleci do sieci. Dlatego działają nawet wtedy, gdy połączenie z serwerem jest martwe.

Trzy rzeczy do zapamiętania

  • Sekwencje działają wyłącznie na początku linii - zawsze najpierw Enter.
  • Znaków ~ i kolejnego klawisza nie widać na ekranie - to normalne.

Ratowanie zawieszonej sesji#

Sytuacja Sekwencja
Terminal wisi, Ctrl+C nie działa Enter ~ .
Sesja w sesji (SSH wewnątrz SSH) Enter ~ ~ .
Chcę odłożyć sesję na chwilę Enter ~ Ctrl+Z, powrót przez fg
Nie pamiętam skrótów Enter ~ ?

Reguła zagnieżdżenia: liczba tyld = jak głęboko w łańcuchu sięgasz. ~. zamyka zawsze pierwsze (najbardziej zewnętrzne) połączenie - czyli wszystko. Odwrotnie: żeby dobić się do najgłębszej sesji (np. 3 SSH w SSH w SSH), trzeba dać ~~~. - każda dodatkowa tylda „przebija” jedną warstwę klientów po drodze.

Pełna lista sekwencji#

Sekwencja Działanie
~. Rozłącz sesję
~^Z Uśpij SSH w tle
~# Lista przekierowanych połączeń
~& Przenieś SSH w tło przy wylogowaniu
~? Pomoc — lista sekwencji
~B Wyślij BREAK do zdalnej strony
~C Otwórz linię poleceń klienta SSH
~R Wymuś ponowną wymianę kluczy (rekeying)
~V / ~v Zmniejsz / zwiększ poziom logowania
~~ Wyślij dosłowną tyldę

~C - zmiana przekierowań w locie#

Pozwala dodać lub usunąć forwarding bez rozłączania sesji. Po Enter ~ Shift+C pojawia się znak zachęty ssh>, w którym wpisujesz:

ssh> - linia poleceń klienta
-L 8080:localhost:80      # lokalne przekierowanie
-R 2222:localhost:22      # zdalne przekierowanie
-D 1080                   # dynamiczne (SOCKS proxy)
-KL 8080                  # usuń przekierowanie lokalne
-KR 2222                  # usuń przekierowanie zdalne
-KD 1080                  # usuń dynamiczne

Uwaga

~C działa tylko na sesji, która faktycznie ma otwarty kanał do klienta (nie zadziała przez multiplekser innej sesji - patrz zarządzanie multiplekserem).

Gdy ~. nie działa#

  1. Naciśnij Enter jeszcze raz i powtórz - najczęstsza przyczyna: linia nie była pusta.
  2. Program pełnoekranowy (vim, less, top) - kilka razy Enter, potem sekwencja.
  3. Dead key na klawiaturze (układ DE/FR/ES) - naciśnij ~, a potem Space, żeby tylda faktycznie została wysłana.
  4. Wyłączony escape char (ssh -e none) - sekwencje nie działają w ogóle.
  5. ControlMaster (multipleksowanie) - sekwencje ucieczki obsługuje proces-master, nie sesja potomna. Jeśli ~. w sesji potomnej nic nie robi, zamknij ją z osobnego terminala poleceniem ssh -O exit user@host.

Awaryjnie, z drugiego terminala:

$ pkill -f "ssh user@host"

Wyłączanie / zmiana znaku ucieczki#

$ ssh -e none user@host     # wyłącz całkowicie
$ ssh -e '^]' user@host     # zmień na Ctrl+]

Na stałe:

~/.ssh/config
Host *
    EscapeChar ~

Wyłączenie przydaje się przy przesyłaniu danych binarnych przez tunel.

Co dzieje się ze zdalnym procesem#

~. zabija lokalnego klienta, ale nie sprząta po stronie serwera. Zdalny sshd zauważy zerwanie dopiero po swoim timeoucie i wyśle SIGHUP procesom w sesji - proces uruchomiony na pierwszym planie najpewniej zginie.

Dlatego długie zadania uruchamiaj w tmux / screen:

$ tmux new -s robota        # start
$ tmux attach -t robota     # po rozłączeniu: powrót, zadanie leci dalej

Zapobieganie zwisom#

Wisząca sesja to zwykle brak keepalive:

~/.ssh/config
Host *
    ServerAliveInterval 30
    ServerAliveCountMax 3
    TCPKeepAlive yes

Klient co 30 s pyta serwer, czy żyje. Po trzech nieudanych próbach zrywa połączenie — czyli po ~90 sekundach zamiast po kilkunastu minutach timeoutu TCP.

Po stronie serwera odpowiednikiem jest:

/etc/ssh/sshd_config
ClientAliveInterval 30
ClientAliveCountMax 3

Przydatne opcje połączenia#

Opcja Zastosowanie
ssh -v / -vvv Diagnostyka problemów z połączeniem
ssh -N Bez zdalnego shella (sam tunel)
ssh -f Przejdź w tło po uwierzytelnieniu
ssh -J host1 host2 Jump host (ProxyJump)
ssh -o "ControlMaster=auto" Multipleksowanie połączeń

Multipleksowanie na stałe - kolejne sesje do tego samego hosta zestawiają się natychmiast:

~/.ssh/config
Host *
    ControlMaster auto
    ControlPath ~/.ssh/cm-%r@%h:%p
    ControlPersist 10m

Zarządzanie multiplekserem#

Gdy sesje idą przez ControlMaster, sekwencje ucieczki (~.) działają nietypowo, bo wiele „sesji” to w rzeczywistości jedno połączenie TCP z procesem-masterem. Zamiast tego steruje się flagą -O:

$ ssh -O check user@host     # czy master żyje i jaki ma PID
$ ssh -O stop user@host      # master przestaje przyjmować nowe sesje, istniejące działają
$ ssh -O exit user@host      # zamknij master i wszystkie sesje na nim oparte
$ ssh -O forward user@host   # dołóż forwarding zdefiniowany dodatkowymi -L/-R/-D

Przydatne, gdy ControlPersist trzyma martwe połączenie (np. po zmianie IP serwera) i nowe próby połączenia zawisają na starym gnieździe - ssh -O exit czyści to bez czekania na timeout.