Як автоматично запустити tmux на сеансі SSH?


92

У мене є близько десяти серверів, до яких я регулярно підключаюся до SSH. Кожен має запис у ~/.ssh/configфайлі мого локального комп’ютера .

Щоб уникнути втрати контролю над своїм запущеним процесом, коли моє з’єднання з Інтернетом неминуче падає, я завжди працюю всередині tmuxсеансу. Я хотів би мати спосіб, щоб tmux автоматично підключався кожного разу, коли запускається з'єднання SSH, тому мені не потрібно завжди вводити текст tmux attach || tmux newпісля введення SSH.

На жаль, це виявляється не так просто, як я спочатку сподівався.

  • Я не хочу додавати жодних команд до ~/.bashrcсерверів, оскільки я хочу це лише для сеансів SSH, а не для локальних сесій.
  • Додавання tmux attach || tmux newдо ~/.ssh/rcна серверах просто призводить до помилки, not a terminalщо виникає після підключення, навіть коли RequestTTY forceопція додана до рядка для цього сервера в моєму локальному файлі конфігурації SSH.

1
Оскільки це питання продовжує залишатися популярним і конкретно згадується ~/.ssh/config: більшість із вас, хто приходить сюди, мабуть, шукає не будь-яку з перших п’яти відповідей, а шосту ( stackoverflow.com/a/52838493/5354137 ). У будь-якій досить недавній tmuxверсії це також найбільш розумний спосіб робити.
Шістдесят п’ять

Відповіді:


90

Конфігурація на стороні сервера:

Щоб автоматично запускати tmux на віддаленому сервері під час звичайного входу через SSH (і лише SSH), відредагуйте відповідним чином ~/.bashrcсвій користувач або root (або обидва) на віддаленому сервері:

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

Ця команда створює сеанс tmux, що викликається, ssh_tmuxякщо такий не існує, або повторно підключається до вже існуючого сеансу з таким іменем. Якщо ваше з’єднання перервалося або ви забули сесію кілька тижнів тому, кожен вхід до SSH автоматично повертає вас до сеансу tmux-ssh, який ви залишили.

Підключіться від клієнта:

Нічого особливого, просто ssh user@hostname.


4
Я шукав це, також я використовував фрагмент коду, дуже схожий на ваш, деякий час тому, але сеанс був іменем користувача (змінився ssh_tmuxна $USER)
Iacchus

3
Див moneytoo в відповідь на корисний коментар по $SSH_TTYпорівнянні $SSH_CONNECTIONтеж.
Містер Тао,

2
ви можете використовувати tmux new-session -A -s ssh_tmuxдля заміни tmux attach-session -t ssh_tmux || tmux new-session -s ssh_tmuxнабагато коротше, якщо трохи заплутаніше, -Aговорить tmux приєднати сесію, якщо вона вже існує
Градієнт

3
Щоб уникнути розбиття "scp", вам також потрібно перевірити, чи це інтерактивна оболонка:if [[ -n "$PS1" ]] && [[ -z "$TMUX" ]] && [[ -n "$SSH_CONNECTION" ]];
janfrode

2
@janfrode не покладайтесь на $PS1, використовуйте [[ $- == *i* ]]замість нього, оскільки PS1 може бути визначений навіть тоді, коли це не інтерактивна оболонка.
Енріко

54

Добре, я знайшов переважно задовільне рішення. У своєму локалі ~/.bashrcя написав функцію:

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

який в основному перезаписує функцію терміналу ssh для виклику вбудованої програми ssh із заданими аргументами, після чого "tmux attach || tmux new".

( $@Позначає всі аргументи, подані в командному рядку, тому ssh -p 123 user@hostnameбуде розширено до ssh -t -p 123 user@hostname "tmux attach || tmux new")

( -tАргумент еквівалентний RequestTTY Forceі необхідний для команди tmux.)


22
Якщо ваша версія tmuxпідтримує його, подумайте про те, tmux new -A fooякий із них буде приєднаний до існуючого сеансу з іменем, fooякщо це можливо, створивши його за необхідності. Це дозволяє спростити вашу функцію /usr/bin/ssh -t "$@" tmux new -A(і обов’язково цитуйте $@!).
Чепнер

1
Примітка: якщо на деяких машинах, до яких ви регулярно підключаєтесь, не встановлено tmux, ви можете сказати щось function sshtподібне, щоб ви могли продовжувати sshнормально користуватися. В іншому випадку просто введіть /usr/bin/sshу командному рядку, коли підключаєтесь до машини без tmux :)
Alex Ryan

1
Якщо ви ліниві, ви можете просто використовувати ssht для підключення до віддалених сеансів tmux. Користувачі OS X можуть торкнутися його за допомогою Brew, а користувачі Linux можуть створити пакет через fpm за допомогою цього файлу Makefile або просто скопіювати sshtв ~/bin.
brejoc

1
Ха-ха приємно! Мені здається трохи надмірним, щоб обернути цей баш однокласний в цілий репо Github за допомогою Makefiles і заварювати, і таке, але привіт, чим легше, тим краще!
Alex Ryan

1
Вирішено:ssh -t user@hostname "LANG=$LANG tmux attach || tmux new"
alecdwm

23

Підключення:

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

Під час сеансу:

Використовуйте Ctrl+dдля завершення сеансу (вікно tmux закривається) або Ctrl+b dдля тимчасового відключення від сеансу та підключення до нього знову пізніше.

Запам’ятай! Якщо ваш сервер перезапущений сеанс втрачено!

Коли ви знаходитесь всередині tmux будь-коли, ви можете використовувати Ctrl+b sдля перегляду списку сеансів та перемикання поточного на інший.

Виправте .bashrc:

Я рекомендую вам визначити універсальну функцію у вашому .bashrc:

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

Він використовує 22порт за замовчуванням. Визначте також свої псевдоніми для швидкого підключення:

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

Увійти без пароля:

І якщо ви не хочете вводити пароль щоразу, тоді генеруйте .sshключі для автоматичного входу :

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

Помістіть свій відкритий ключ на віддалений хост:

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

Додаткові поради:

Якщо ви хочете використовувати тимчасовий ідентифікатор сеансу, який відповідає локальному сеансу bash, використовуйте як ідентифікатор tmux :

SID=$USER-$BASHPID
ssh user@host -t "tmux new-session -s $SID || tmux attach-session -t $SID"

1
Акуратний трюк , щоб уникнути цього ||в деяких споживчих випадках повинна включати new-sessionв .tmux.confі просто завжди використовувати tmux a -t 0.
Флоріан Вендельборн,

4
У новіших версіях tmux ви також можете використовувати tmux new-session -Aприкріплений файл, якщо він існує, інакше він створить новий.
dragon788

15

Я використав рядки з @kingmeffisto (мені не дозволено коментувати цю відповідь), і я додав вихід, тому завершення tmux також припиняє з'єднання ssh. Однак це зламало сеанси SFTP, тому мені довелося перевірити $SSH_TTYзамість $SSH_CONNECTION.

EDIT 4/2018: Додано тест для інтерактивного терміналу через, [[ $- =~ i ]]щоб дозволити працювати таким інструментам, як Ansible.

if [ -z "$TMUX" ] && [ -n "$SSH_TTY" ] && [[ $- =~ i ]]; then
    tmux attach-session -t ssh || tmux new-session -s ssh
    exit
fi

14

Як описано в цій публікації в блозі, ви можете ssh, а потім приєднатись до існуючого сеансу tmux за допомогою однієї команди:

ssh hostname -t tmux attach -t 0

Це те, що робить моя відповідь (хоча я використовую tmux attach || tmux newтак, щоб новий сеанс tmux не створювався для кожного з’єднання). Хитра частина полягає в тому, що правильна команда є, ssh -t user@host tmux attach || tmux newі єдиний спосіб встановити псевдонім того, що потребує аргументу всередині командного рядка, - це створити нову функцію, як я це робив вище.
Alex Ryan

Я знаю, але деякі люди (як я) можуть віддати перевагу
однокласснику

3
Це підключається до сеансу під назвою '0'. Тобто загальна форма такаssh [hostname] -t tmux attach -t [sessionName]
Девід Дорія

1
Це дуже добре спрацювало для мене .. У поєднанні це буде unix.stackexchange.com/a/116674 .. так що тепер мій графічний інтерфейс шпаклівки виглядає так .. imgur.com/uFhxN30 . Я можу відключити сеанси за допомогою Cntrl + b + d. Дуже просто і зручно ..
alpha_989

14

tmux 3.1 або новішої версії¹ на віддаленій машині

До вашого місцевого ~/.ssh/config, покладіть²:

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

Не пов’язано, але якщо ви маєте справу з символами, що не належать до ASCII, я рекомендую змінити це на tmux -u … щоб явно включити підтримку Unicode навіть на машинах, у яких не встановлено належних змінних середовища.

tmux 3.0a або старішої версії на віддаленому комп'ютері

Майже те саме, що і вище, але змініть останній рядок на³:

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

¹ Станом на 2020-10-29, список дистрибутивів постачається з tmux 3.1 або новішою вже досить довгий.

² new- це скорочення від new-session.

³ at- це скорочення від attach-session.


Альтернативний метод використання authorized_keysфайлу пульта :

Якщо ви хотіли б не мати ~/.ssh/configфайлу з будь-якої причини або хочете, щоб віддалена машина змусила приєднувальну машину підключитися до / відкрити сеанс, додайте це на свій пульт ~/.ssh/authorized_keys:

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

Звичайно, це працюватиме з усіма клієнтами, у яких встановлений відповідний закритий ключ, який може бути як плюсом, так і мінусом, залежно від того, що ви хочете. Існує ризик того, що, якщо щось піде не так, можливо, більше неможливо буде підключитися.


чому tmux atзамість tmux a? Також було б розумно використовувати для цього названий сеанс, або tmux приєднався б до "випадкових" існуючих сеансів після входу в хост.
Ерік

Як ви призупиняєте сеанс tmux? ssh після удару переходить у стан невидимості Ctrl+A Ctrl+Z.
Ерік

Це просто відключається. Що стосується мене, то такої поведінки я очікував би і я задоволений.
Шістдесят п’ять

1
Ctrl-B Dтвори лікувати порівняно з Ctrl-B Ctrl-Z. Дякую!
Ерік

1
Це має бути, імхо, найбільш голосованою відповіддю. Я шукав саме (2).
cduguet

1

byobu - приємна корисна обгортка для tmux / screen. Підключається до існуючого сеансу, якщо він присутній, або створює новий.

Я використовую його з autossh, який витончено підключає сеанс ssh. Настійно рекомендується у разі непостійних проблем із підключенням.

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'
}

1

Вам це може виявитися корисним - використовує ssh у циклі та повторно підключається до існуючого сеансу tmux або підключається до нього, тому у вас є хороший, простий і надійний спосіб відновити зв’язок після відключення мережі

#!/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

1

Це те, що насправді створює чудовий досвід користувачів. Він автоматично запускає tmux щоразу, коли ви відкриваєте термінал (як фізично, так і ssh). Ви можете розпочати свою роботу на одному пристрої, вийти з терміналу та продовжити роботу на іншому. Якщо виявить когось, хто вже приєднався до сеансу, він створить новий сеанс. Помістіть його на сервер , залежно від вашої оболонки ~/.zshrcабо ~/.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

0

Я знаю, що я відроджую старий потік, але я провів деяку роботу над рішенням bashrc, і я думаю, що він має певну користь:

#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

Наразі обмеження на 10 (11) сеансів - я не хотів вбивати свій сервер нескінченним циклом у bashrc. Здається, це працює досить надійно, крім помилки tmux, яка не працює на списках-клієнтах, якщо сеансу не існує.


0

Цей спосіб дозволяє вам підключитися до старого екземпляра tmux, якщо ваш сеанс ssh знизиться. execЗаощаджує вилку звичайно.

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.