Jak automatycznie uruchomić tmux w sesji SSH?

92

Mam około dziesięciu serwerów, z którymi regularnie łączę się przez SSH. Każdy ma wpis w ~/.ssh/configpliku mojego komputera lokalnego .

Aby uniknąć utraty kontroli nad uruchomionym procesem, gdy moje połączenie internetowe nieuchronnie spada, zawsze pracuję w ramach tmuxsesji. Chciałbym mieć możliwość automatycznego łączenia się tmux za każdym razem, gdy uruchamiane jest połączenie SSH, więc nie muszę zawsze wpisywać tmux attach || tmux newpo wejściu SSH.

Niestety nie okazuje się to tak proste, jak początkowo liczyłem.

  • Nie chcę dodawać żadnych poleceń do ~/.bashrcna serwerach, ponieważ chcę to tylko dla sesji SSH, a nie sesji lokalnych.
  • Dodanie tmux attach || tmux newdo ~/.ssh/rcna serwerach powoduje po prostu not a terminalwyrzucenie błędu po połączeniu, nawet jeśli RequestTTY forceopcja jest dodana do wiersza tego serwera w moim lokalnym pliku konfiguracyjnym SSH.
Alex Ryan
źródło
1
Ponieważ jest to nadal popularne pytanie i wyraźnie wspomina ~/.ssh/config: większość z was, którzy przyjeżdżają tutaj, prawdopodobnie nie szuka żadnej z pierwszych pięciu odpowiedzi, ale szóstej ( stackoverflow.com/a/52838493/5354137 ). Z każdą stosunkowo najnowszą tmuxwersją jest to również najbardziej rozsądny sposób robienia rzeczy.
Sixtyfive

Odpowiedzi:

90

Konfiguracja po stronie serwera:

Aby automatycznie uruchomić tmux na serwerze zdalnym podczas zwykłego logowania przez SSH (i tylko SSH), odpowiednio edytuj ~/.bashrcużytkownika lub root (lub oba) na serwerze zdalnym:

if [[ -n "$PS1" ]] && [[ -z "$TMUX" ]] && [[ -n "$SSH_CONNECTION" ]]; then
  tmux attach-session -t ssh_tmux || tmux new-session -s ssh_tmux
fi

To polecenie tworzy sesję tmux o nazwie, ssh_tmuxjeśli żadna nie istnieje, lub ponownie podłącza się do już istniejącej sesji o tej nazwie. W przypadku zerwania połączenia lub gdy zapomniałeś sesji kilka tygodni temu, każde logowanie SSH automatycznie przenosi Cię z powrotem do sesji tmux-ssh, którą zostawiłeś.

Połącz się z klientem:

Po prostu nic specjalnego ssh user@hostname.

kingmeffisto
źródło
4
Szukałem tego, również użyłem fragmentu kodu bardzo podobnego do twojego jakiś czas temu, ale sesja była nazwą użytkownika (zmiana ssh_tmuxna $USER)
Iacchus
3
Zobacz moneytoo za odpowiedź dla użytecznego komentarzu $SSH_TTYvs $SSH_CONNECTIONteż.
Mr. Tao
2
możesz użyć tmux new-session -A -s ssh_tmuxdo zastąpienia tmux attach-session -t ssh_tmux || tmux new-session -s ssh_tmuxznacznie krótszego, jeśli nieco bardziej mylącego, -Amówi tmuxowi, aby dołączył sesję, jeśli już istnieje
Gradient
3
Aby uniknąć złamania "scp", musisz również sprawdzić, czy to jest powłoka interaktywna:if [[ -n "$PS1" ]] && [[ -z "$TMUX" ]] && [[ -n "$SSH_CONNECTION" ]];
janfrode
2
@janfrode nie polega na $PS1, [[ $- == *i* ]]zamiast tego użyj , ponieważ PS1 może być zdefiniowane nawet wtedy, gdy nie jest powłoką interaktywną.
Enrico
53

W porządku, znalazłem w większości satysfakcjonujące rozwiązanie. W moim lokalnym ~/.bashrcnapisałem funkcję:

function ssh () {/usr/bin/ssh -t $@ "tmux attach || tmux new";}

co zasadniczo nadpisuje funkcję terminala ssh, aby wywołać wbudowany program ssh z podanymi argumentami, po których następuje "tmux attach || tmux new".

(Symbol $@oznacza wszystkie argumenty podane w linii poleceń, więc ssh -p 123 user@hostnamezostanie rozwinięty do ssh -t -p 123 user@hostname "tmux attach || tmux new")

( -tArgument jest równoważny z RequestTTY Forcepoleceniem tmux i jest dla niego niezbędny).

Alex Ryan
źródło
22
Jeśli Twoja wersja tmuxobsługuje tę funkcję, rozważ użycie, tmux new -A fooktóre dołączy do istniejącej sesji o nazwie, foojeśli to możliwe, tworząc ją w razie potrzeby. Pozwala to uprościć funkcję /usr/bin/ssh -t "$@" tmux new -A(i koniecznie zacytować $@!).
chepner
1
Uwaga: jeśli na niektórych maszynach, z którymi regularnie się łączysz, nie ma zainstalowanego tmux, możesz powiedzieć function sshtlub coś podobnego, aby móc nadal sshnormalnie używać . W przeciwnym razie po prostu wpisz /usr/bin/sshw wierszu polecenia za każdym razem, gdy łączysz się z komputerem bez tmux :)
Alex Ryan
1
Jeśli jesteś leniwy, możesz po prostu użyć ssht, aby połączyć się ze zdalnymi sesjami tmux. Użytkownicy OS X mogą go wykorzystać przez brew, a użytkownicy Linuksa mogą stworzyć pakiet przez fpm z tym Makefile lub po prostu skopiować sshtdo ~/bin.
brejoc
1
Haha fajnie! Wydaje mi się, że to trochę przesada, żebym zawinął ten jeden-liniowiec w całe repozytorium Github z plikami Makefiles i piwem i tak dalej, ale hej, im łatwiej, tym lepiej!
Alex Ryan
1
Rozwiązany:ssh -t user@hostname "LANG=$LANG tmux attach || tmux new"
alecdwm
23

Połączyć:

ssh user@host -t "tmux new-session -s user || tmux attach-session -t user"

Podczas sesji:

Służy Ctrl+ddo kończenia sesji (zamykanie okna tmux) lub Ctrl+b ddo tymczasowego odłączania się od sesji i ponownego łączenia się z nią później.

Zapamiętaj! Jeśli serwer zrestartował sesję, przegrana!

Kiedy jesteś w środku tmux w dowolnym momencie, możesz użyć, Ctrl+b saby wyświetlić listę sesji i przełączyć się na inną.

Napraw swój .bashrc:

Polecam zdefiniowanie funkcji uniwersalnej w .bashrc:

function tmux-connect {
    TERM=xterm-256color ssh -p ${3:-22} $1@$2 -t "tmux new-session -s $1 || tmux attach-session -t $1"
}

22Domyślnie używa portu. Zdefiniuj również aliasy do szybkiego łączenia:

alias office-server='tmux-connect $USER 192.168.1.123'
alias cloud-server='tmux-connect root my.remote.vps.server.com 49281'

Zaloguj się bez hasła:

A jeśli nie chcesz za każdym razem wpisywać hasła, to generować .sshklucze do automatycznego logowania :

ssh-keygen -t rsa
eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_rsa

Umieść swój klucz publiczny na zdalnym hoście:

ssh-copy-id -p <port> user@hostname

Dodatkowe wskazówki:

Jeśli chcesz użyć tymczasowego identyfikatora sesji, który odpowiada lokalnej sesji bash, użyj jako identyfikatora tmux :

SID=$USER-$BASHPID
ssh user@host -t "tmux new-session -s $SID || tmux attach-session -t $SID"
DenisKolodin
źródło
1
Zgrabny sztuczka w celu uniknięcia że ||w niektórych przypadkach użytkowych jest włączenie new-sessionw .tmux.confi tak zawsze używać tmux a -t 0.
Florian Wendelborn
4
W nowszych wersjach tmux możesz również użyć, tmux new-session -Aktóry dołączy, jeśli istnieje, w przeciwnym razie utworzy nowy.
dragon788
15

Użyłem linii z @kingmeffisto (nie mogę komentować tej odpowiedzi) i dodałem wyjście, więc zakończenie tmux również kończy połączenie ssh. To jednak zepsuło sesje SFTP, więc $SSH_TTYzamiast tego musiałem sprawdzić $SSH_CONNECTION.

EDYCJA 4/2018: Dodano test dla interaktywnego terminala za pośrednictwem, [[ $- =~ i ]]aby umożliwić działanie narzędzi takich jak Ansible.

if [ -z "$TMUX" ] && [ -n "$SSH_TTY" ] && [[ $- =~ i ]]; then
    tmux attach-session -t ssh || tmux new-session -s ssh
    exit
fi
moneytoo
źródło
14

Jak opisano w tym poście na blogu , możesz ssh, a następnie dołączyć do istniejącej sesji tmux za pomocą jednego polecenia:

ssh hostname -t tmux attach -t 0
Fabian Pedregosa
źródło
Tak właśnie działa moja odpowiedź (chociaż używam, tmux attach || tmux newaby nowa sesja tmux nie była tworzona dla każdego połączenia). Problem polega na tym, że prawidłowe polecenie jest ssh -t user@host tmux attach || tmux newi jedynym sposobem na aliasowanie czegoś, co wymaga argumentu w ciągu polecenia, jest utworzenie nowej funkcji, tak jak zrobiłem powyżej.
Alex Ryan,
Wiem, ale niektórzy ludzie (tacy jak ja) mogą preferować
jednolinijkowy tekst
3
To łączy się z sesją o nazwie „0”. To znaczy, ogólna forma tossh [hostname] -t tmux attach -t [sessionName]
David Doria
1
To zadziałało dla mnie naprawdę dobrze .. W połączeniu to będzie unix.stackexchange.com/a/116674 .. więc teraz mój GUI kit wygląda tak ... imgur.com/uFhxN30 . Mogę rozłączyć sesje z Cntrl + b + d. Bardzo proste i wygodne ..
alpha_989
14

tmux 3.1 lub nowszy¹ na komputerze zdalnym

W lokalu ~/.ssh/configwpisz²:

Host myhost
  Hostname host
  User user
  RequestTTY yes
  RemoteCommand tmux new -A -s foobar

Bez związku, ale jeśli masz do czynienia ze znakami spoza zestawu ASCII, zalecałbym zmianę tego na, tmux -u …aby jawnie włączyć obsługę Unicode nawet na maszynach, które nie mają ustawionych odpowiednich zmiennych środowiskowych.

tmux 3.0a lub starsze na komputerze zdalnym

Prawie to samo co powyżej, ale zmień ostatni wiersz na³:

  RemoteCommand tmux at -t foobar || tmux new -s foobar

¹ Na dzień 2020-10-29 lista dystrybucji z tmux 3.1 lub nowszym jest już dość długa.

² newto skrót od new-session.

³ atto skrót od attach-session.


Alternatywna metoda wykorzystująca authorized_keysplik pilota :

Jeśli wolisz nie mieć ~/.ssh/configpliku z jakiegokolwiek powodu lub chcesz, aby zdalny komputer wymusił połączenie się / otwarcie sesji na maszynie łączącej, dodaj to do swojego pilota ~/.ssh/authorized_keys:

command="tmux at -t foobar || tmux new -s foobar" pubkey user@client

Będzie to oczywiście działać na wszystkich klientach, którzy mają zainstalowany odpowiedni klucz prywatny, co może być wadą lub wadą, w zależności od tego, czego chcesz. Istnieje ryzyko, że jeśli coś pójdzie nie tak, połączenie może nie być już możliwe.

Sześćdziesiąt pięć
źródło
dlaczego tmux atzamiast tmux a? Dobrze byłoby też użyć do tego nazwanej sesji, w przeciwnym razie tmux połączyłby się z „losowymi” istniejącymi sesjami po zalogowaniu się do hosta.
Eric
Jak zawiesić sesję tmux? ssh przechodzi w stan limbo kindda po uderzeniu Ctrl+A Ctrl+Z.
Eric
Po prostu się rozłącza. Jeśli o mnie chodzi, takiego zachowania bym się spodziewał iz którego jestem zadowolony.
Sixtyfive
1
Ctrl-B Dprace traktują w porównaniu do Ctrl-B Ctrl-Z. Dzięki!
Eric
1
To powinna być, imho, najczęściej głosowana odpowiedź. Szukałem dokładnie (2).
cduguet
1

byobu to przydatne opakowanie tmux / screen. Łączy się z istniejącą sesją, jeśli jest obecna, lub tworzy nową.

Używam go z autosshem, który z wdziękiem ponownie łączy sesję ssh. Wysoce zalecane w przypadku sporadycznych problemów z łącznością.

function ssh-tmux(){
  if ! command -v autossh &> /dev/null; then echo "Install autossh"; fi
  autossh -M 0 $* -t 'byobu || {echo "Install byobu-tmux on server..."} && bash'
}
Sandeep
źródło
1

Może Ci się to przydać - używa ssh w pętli i ponownie łączy się z istniejącą sesją tmux lub łączy się z nią, dzięki czemu masz łatwy, niezawodny sposób na ponowne połączenie po awarii sieci

#!/bin/bash
#
# reconnect to or spawn a new tmux session on the remote host via ssh.
# If the network connection is lost, ssh will reconnect after a small
# delay.
#

SSH_HOSTNAME=$1
TMUX_NAME=$2
PORT=$3

if [[ "$PORT" != "" ]]
then
    PORT="-p $PORT"
fi

if [ "$TMUX_NAME" = "" ]
then
    SSH_UNIQUE_ID_FILE="/tmp/.ssh-UNIQUE_ID.$LOGNAME"

    if [ -f $SSH_UNIQUE_ID_FILE ]
    then
        TMUX_NAME=`cat $SSH_UNIQUE_ID_FILE`
        TMUX_NAME=`expr $TMUX_NAME + $RANDOM % 100`
    else
        TMUX_NAME=`expr $RANDOM % 1024`
    fi

    echo $TMUX_NAME > $SSH_UNIQUE_ID_FILE

    TMUX_NAME="id$TMUX_NAME"
fi

echo Connecting to tmux $TMUX_NAME on hostname $SSH_HOSTNAME

SLEEP=0
while true; do

    ssh $PORT -o TCPKeepAlive=no -o ServerAliveInterval=15 -Y -X -C -t -o BatchMode=yes $SSH_HOSTNAME "tmux attach-session -t $TMUX_NAME || tmux -2 -u new-session -s $TMUX_NAME"
    SLEEP=10
    if [ $SLEEP -gt 0 ]
    then
        echo Reconnecting to session $TMUX_NAME on hostname $SSH_HOSTNAME in $SLEEP seconds
        sleep $SLEEP
    fi
done
Neil McGill
źródło
1

To właśnie tworzy wspaniałe wrażenia użytkownika. Automatycznie uruchamia tmux za każdym razem, gdy otworzysz terminal (zarówno fizycznie, jak i ssh). Możesz rozpocząć pracę na jednym urządzeniu, wyjść z terminala i wznowić na drugim. Jeśli wykryje kogoś już dołączonego do sesji, utworzy nową sesję. Umieść go na serwerze , w zależności od powłoki ~/.zshrclub ~/.bashrc.

 if [[ -z "$TMUX" ]] ;then
     ID="$( tmux ls | grep -vm1 attached | cut -d: -f1 )" # get the id of a deattached session
     if [[ -z "$ID" ]] ;then # if not available attach to a new one
         tmux new-session
     else
         tmux attach-session -t "$ID" # if available attach to it
     fi
fi
Stanisław Barański
źródło
0

Wiem, że przywracam stary wątek, ale trochę popracowałem nad rozwiązaniem bashrc i myślę, że ma to jakieś zastosowanie:

#attach to the next available tmux session that's not currently occupied
if [[ -z "$TMUX" ]] && [ "SSH_CONNECTION" != "" ];
then
    for i in `seq 0 10`; do #max of 10 sessions - don't want an infinite loop until we know this works
            SESH=`tmux list-clients -t "$USER-$i-tmux" 2>/dev/null` #send errors to /dev/null - if the session doesn't exist it will throw an error, but we don't care
            if [ -z "$SESH" ] #if there's no clients currently connected to this session
            then
                tmux attach-session -t "$USER-$i-tmux" || tmux new-session -s "$USER-$i-tmux" #attach to it
                break #found one and using it, don't keep looping (this will actually run after tmux exits AFAICT)
            fi #otherwise, increment session counter and keep going
    done

fi

Na razie obowiązuje limit 10 (11) sesji - nie chciałem zabijać mojego serwera nieskończoną pętlą w bashrc. Wydaje się, że działa całkiem niezawodnie, z wyjątkiem błędu polegającego na niepowodzeniu tmux na klientach list, jeśli sesja nie istnieje.

Brydon Gibson
źródło
0

Ten sposób umożliwia ponowne połączenie się ze starą instancją tmux, jeśli sesja ssh spadnie. execOszczędza widelec oczywiście.

if [ -z "$TMUX"  ]; then
  pid=$(tmux ls | grep -vm1 "(attached)" | cut -d: -f1)
  if [ -z "$pid" ]; then
    tmux new -d -s $pid
  fi

  exec tmux attach -t $pid
fi
ericcurtin
źródło