Bagaimana cara memulai tmux secara otomatis pada sesi SSH?


92

Saya memiliki sepuluh atau lebih server yang saya sambungkan dengan SSH secara teratur. Masing-masing memiliki entri di ~/.ssh/configfile komputer lokal saya .

Untuk menghindari kehilangan kendali atas proses saya yang sedang berjalan ketika koneksi Internet saya terputus secara tidak terelakkan, saya selalu bekerja di dalam sebuah tmuxsesi. Saya ingin cara agar tmux terhubung secara otomatis setiap kali koneksi SSH dimulai, jadi saya tidak harus selalu mengetik tmux attach || tmux newsetelah saya masuk ke SSH.

Sayangnya ini tidak sesederhana yang saya harapkan semula.

  • Saya tidak ingin menambahkan perintah apa pun ke ~/.bashrcserver karena saya hanya menginginkannya untuk sesi SSH, bukan sesi lokal.
  • Menambahkan tmux attach || tmux newke ~/.ssh/rcpada server hanya menghasilkan kesalahan yang not a terminalterjadi setelah koneksi, bahkan ketika RequestTTY forceopsi ditambahkan ke baris untuk server itu di file konfigurasi SSH lokal saya.

1
Karena ini terus menjadi pertanyaan populer dan secara khusus menyebutkan ~/.ssh/config: sebagian besar dari Anda yang datang ke sini mungkin tidak mencari salah satu dari lima jawaban pertama, tetapi untuk yang keenam ( stackoverflow.com/a/52838493/5354137 ). Dengan tmuxversi yang cukup baru, itu juga cara yang paling masuk akal dalam melakukan sesuatu.
Enam puluh lima

Jawaban:


90

Konfigurasi sisi server:

Untuk memulai tmux secara otomatis di server jarak jauh Anda saat biasanya masuk melalui SSH (dan hanya SSH), edit ~/.bashrcpengguna atau root Anda (atau keduanya) di server jarak jauh sesuai:

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

Perintah ini membuat sesi tmux dipanggil ssh_tmuxjika tidak ada, atau melampirkan kembali ke sesi yang sudah ada dengan nama itu. Jika koneksi Anda terputus atau ketika Anda lupa sesi beberapa minggu yang lalu, setiap login SSH secara otomatis membawa Anda kembali ke sesi tmux-ssh yang Anda tinggalkan.

Terhubung dari klien Anda:

Tidak ada yang istimewa, hanya ssh user@hostname.


4
Saya mencari ini, juga saya menggunakan sepotong kode yang sangat mirip dengan milik Anda beberapa waktu lalu, tetapi sesinya adalah nama pengguna (berubah ssh_tmuxmenjadi $USER)
Iacchus

3
Lihat jawaban moneytoo untuk komentar berguna tentang $SSH_TTYvs $SSH_CONNECTIONjuga.
Tn. Tao

2
Anda dapat menggunakan tmux new-session -A -s ssh_tmuxuntuk mengganti tmux attach-session -t ssh_tmux || tmux new-session -s ssh_tmuxjauh lebih pendek, jika sedikit lebih membingungkan, -Amemberitahu tmux untuk melampirkan sesi jika sudah ada
Gradient

3
Untuk menghindari kerusakan "scp", Anda juga perlu memeriksa apakah ini shell interaktif:if [[ -n "$PS1" ]] && [[ -z "$TMUX" ]] && [[ -n "$SSH_CONNECTION" ]];
janfrode

2
@janfrode tidak bergantung pada $PS1, gunakan [[ $- == *i* ]]sebagai gantinya, karena PS1 dapat didefinisikan meskipun itu bukan shell interaktif.
Enrico

54

Baiklah, saya menemukan solusi yang sebagian besar memuaskan. Di lokal saya ~/.bashrc, saya menulis sebuah fungsi:

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

yang pada dasarnya menimpa fungsi terminal ssh untuk memanggil program ssh built-in dengan argumen yang diberikan, diikuti oleh "tmux attach || tmux new".

( $@Menunjukkan semua argumen yang disediakan pada baris perintah, jadi ssh -p 123 user@hostnameakan diperluas ke ssh -t -p 123 user@hostname "tmux attach || tmux new")

( -tArgumennya setara dengan RequestTTY Forcedan diperlukan untuk perintah tmux.)


22
Jika versi Anda tmuxmendukungnya, pertimbangkan untuk menggunakan tmux new -A fooyang akan melampirkan ke sesi yang ada bernama foojika memungkinkan, membuatnya jika perlu. Ini memungkinkan Anda menyederhanakan fungsi Anda menjadi /usr/bin/ssh -t "$@" tmux new -A(dan pastikan untuk mengutip $@!).
chepner

1
Catatan: jika beberapa mesin yang Anda hubungkan secara teratur tidak menginstal tmux, Anda mungkin ingin mengatakan function sshtatau sejenisnya sehingga Anda dapat terus menggunakan secara sshnormal. Jika tidak, cukup ketik /usr/bin/sshdi command prompt setiap kali menghubungkan ke mesin tanpa tmux :)
Alex Ryan

1
Jika Anda malas, Anda dapat menggunakan ssht untuk menghubungkan sesi tmux jarak jauh Anda. Pengguna OS X dapat mengetuknya melalui brew dan pengguna Linux dapat membuat paket melalui fpm dengan Makefile ini atau cukup salin sshtke ~/bin.
brejoc

1
Haha bagus! Sepertinya sedikit berlebihan bagi saya untuk membungkus bash satu baris ini di seluruh repo Github dengan Makefiles dan minuman dan semacamnya tapi hei, semakin mudah semakin baik!
Alex Ryan

1
Dipecahkan:ssh -t user@hostname "LANG=$LANG tmux attach || tmux new"
alecdwm

23

Menghubung:

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

Selama sesi:

Gunakan Ctrl+duntuk menyelesaikan sesi (jendela tmux menutup) atau Ctrl+b duntuk melepaskan sementara dari sesi dan menyambungkannya lagi nanti.

Ingat! Jika server Anda memulai kembali sesi hilang!

Ketika Anda berada di dalam tmux kapan saja Anda dapat menggunakan Ctrl+b suntuk melihat daftar sesi dan beralih saat ini ke yang lain.

Perbaiki .bashrc Anda:

Saya menyarankan Anda untuk menentukan fungsi universal di .bashrc:

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

Ini menggunakan 22port secara default. Tentukan juga alias koneksi cepat Anda:

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

Login tanpa kata sandi:

Dan jika Anda tidak ingin setiap kali mengetik kata sandi daripada menghasilkan .sshkunci untuk masuk secara otomatis :

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

Letakkan kunci publik Anda ke host jarak jauh:

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

Tips tambahan:

Jika Anda ingin menggunakan session-id sementara yang sesuai dengan sesi bash lokal gunakan sebagai tmux id:

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

1
Sebuah trik rapi untuk menghindari bahwa ||dalam beberapa penggunaan-kasus adalah untuk menyertakan new-sessiondalam .tmux.confdan hanya selalu menggunakan tmux a -t 0.
Florian Wendelborn

4
Dalam versi terbaru tmux Anda juga dapat menggunakan tmux new-session -Ayang akan melampirkan jika ada, jika tidak maka akan membuat yang baru.
dragon788

15

Saya menggunakan baris dari @kingmeffisto (Saya tidak diizinkan mengomentari jawaban itu) dan saya menambahkan jalan keluar sehingga menghentikan tmux juga mengakhiri koneksi ssh. Namun ini merusak sesi SFTP jadi saya harus memeriksanya, $SSH_TTYbukan $SSH_CONNECTION.

EDIT 4/2018: Tes tambahan untuk terminal interaktif melalui [[ $- =~ i ]]untuk memungkinkan alat seperti Ansible untuk bekerja.

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

14

Seperti yang dijelaskan dalam posting blog ini, Anda dapat ssh dan kemudian melampirkan ke sesi tmux yang ada dengan satu perintah:

ssh hostname -t tmux attach -t 0

Itulah jawaban saya (meskipun saya menggunakan tmux attach || tmux newsehingga sesi tmux baru tidak dibuat untuk setiap koneksi). Bagian yang sulit adalah bahwa perintah yang benar adalah ssh -t user@host tmux attach || tmux newdan satu-satunya cara untuk membuat alias sesuatu yang membutuhkan argumen di dalam string perintah adalah membuat fungsi baru, seperti yang saya lakukan di atas.
Alex Ryan

Saya tahu, tetapi beberapa orang (seperti saya) mungkin lebih memilih satu kalimat yang tidak melibatkan pendefinisian suatu fungsi
Fabian Pedregosa

3
Ini menghubungkan ke sesi yang disebut '0'. Artinya, bentuk umumnya adalahssh [hostname] -t tmux attach -t [sessionName]
David Doria

1
Ini bekerja dengan sangat baik bagi saya .. Gabungan ini akan unix.stackexchange.com/a/116674 .. jadi sekarang GUI dempul saya terlihat seperti ini .. imgur.com/uFhxN30 . Saya dapat memutuskan sesi dengan Cntrl + b + d. Sangat sederhana dan nyaman ..
alpha_989

14

tmux 3.1 atau yang lebih baru¹ pada mesin jarak jauh

Ke dalam lokal Anda ~/.ssh/config, letakkan²:

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

Tidak terkait, tetapi jika Anda berurusan dengan karakter non-ASCII, saya sarankan untuk mengubahnya menjadi tmux -u …untuk mengaktifkan dukungan Unicode secara eksplisit bahkan pada mesin yang tidak memiliki set variabel lingkungan yang tepat.

tmux 3.0a atau yang lebih lama pada mesin jarak jauh

Hampir sama seperti di atas, tetapi ganti baris terakhir menjadi³:

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

¹ Pada 2020-10-29, daftar pengiriman distribusi dengan tmux 3.1 atau yang lebih baru sudah cukup lama.

² newadalah kependekan dari new-session.

³ atadalah kependekan dari attach-session.


Metode alternatif menggunakan file remote authorized_keys:

Jika Anda lebih suka tidak memiliki ~/.ssh/configfile karena alasan apa pun, atau ingin mesin jarak jauh memaksa mesin penghubung untuk terhubung ke / membuka sesi, tambahkan ini ke remote Anda ~/.ssh/authorized_keys:

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

Ini akan, tentu saja, bekerja dari semua klien yang memiliki kunci pribadi yang sesuai terpasang, yang bisa menjadi naik atau turun, tergantung pada apa yang Anda inginkan. Ada risiko bahwa, jika terjadi kesalahan, mungkin tidak dapat tersambung lagi.


mengapa, tmux atbukan tmux a? Juga akan bijaksana untuk menggunakan sesi bernama untuk ini atau tmux akan melampirkan ke sesi "acak" yang ada saat masuk ke host.
Eric

Bagaimana Anda menangguhkan sesi tmux? ssh masuk ke keadaan limbo setelah memukul Ctrl+A Ctrl+Z.
Eric

Itu hanya terputus. Sejauh yang saya ketahui, itulah perilaku yang saya harapkan dan saya sukai.
Enam puluh lima

1
Ctrl-B Dbekerja memperlakukan dibandingkan Ctrl-B Ctrl-Z. Terima kasih!
Eric

1
Ini seharusnya, imho, jawaban yang paling banyak dipilih. Aku sedang mencari (2).
cduguet

1

byobu adalah pembungkus berguna yang bagus untuk tmux / layar. Menghubungkan ke sesi yang ada jika ada atau membuat yang baru.

Saya menggunakannya dengan autossh yang dengan anggun menghubungkan kembali sesi ssh. Sangat disarankan jika terjadi masalah konektivitas yang terputus-putus.

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

Anda mungkin menemukan ini berguna - menggunakan ssh dalam satu loop dan menyambungkan kembali atau menyambung ke sesi tmux yang ada sehingga Anda memiliki cara yang bagus dan mudah diandalkan untuk menyambung kembali setelah pemadaman jaringan

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

Ini adalah salah satu yang benar-benar menciptakan pengalaman pengguna yang luar biasa. Ini secara otomatis memulai tmux setiap kali Anda membuka terminal (baik secara fisik maupun ssh). Anda dapat memulai pekerjaan Anda di satu perangkat, keluar dari terminal, dan melanjutkan di perangkat lain. Jika mendeteksi seseorang sudah dilampirkan ke sesi itu akan membuat sesi baru. Taruh di server , tergantung pada shell Anda ~/.zshrcatau ~/.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

Saya tahu saya menghidupkan kembali utas lama tetapi saya telah melakukan beberapa pekerjaan pada solusi bashrc dan saya pikir itu ada gunanya:

#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

Ada batasan pada 10 (11) sesi untuk saat ini - saya tidak ingin mematikan server saya dengan loop tak terbatas di bashrc. Tampaknya bekerja dengan cukup andal, selain kesalahan tmux yang gagal pada klien daftar jika sesi tidak ada.


0

Cara ini memungkinkan Anda untuk terhubung kembali ke instance tmux lama jika sesi ssh Anda menurun. The execmenyimpan garpu tentu saja.

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.