SSHセッションでtmuxを自動的に開始する方法は?


100

SSHで定期的に接続するサーバーが10台ほどあります。それぞれが私のローカルコンピュータの~/.ssh/configファイルにエントリを持っています。

インターネット接続が必然的に切断されたときに実行中のプロセスの制御を失うことを避けるために、私は常にtmuxセッション内で作業します。SSH接続が開始されるたびにtmuxが自動的に接続するようにしたいので、tmux attach || tmux newSSHで入力した後に常に入力する必要はありません。

残念ながら、これは私が当初望んでいたほど単純ではありません。

  • ~/.bashrcローカルセッションではなくSSHセッションにのみコマンドが必要なため、サーバー上のコマンドを追加したくありません。
  • 追加tmux attach || tmux new~/.ssh/rcサーバー上では、単にエラーになりnot a terminal場合でも、接続後にスローされるRequestTTY forceオプションは私の地元のSSHの設定ファイルで、そのサーバーのラインに追加されます。

これは引き続き人気のある質問です。tmuxは5年前から大きく変わったことを指摘したいと思います。上位の回答は、シェルを介してこれを行うのではなく、を介してこれを行うというベストプラクティスを反映していません~/.ssh/config。したがって、ほとんどの人がおそらく必要とする答えは、stackoverflow.com / a / 52838493/5354137です。
65

回答:


94

サーバー側の構成:

通常SSH(およびSSHのみ)を介してログインするときにリモートサーバーでtmuxを自動的に起動するには、リモートサーバーで~/.bashrcユーザーまたはルート(またはその両方)のを適宜編集します。

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

このコマンドは、ssh_tmux存在しない場合に呼び出されるtmuxセッションを作成するか、その名前で既存のセッションに再接続します。接続が切断された場合、または数週間前にセッションを忘れた場合、SSHログインごとに、取り残されたtmux-sshセッションに自動的に戻ります。

クライアントから接続します。

特別なことは何もありませんssh user@hostname


4
私はまた、私はいくつかの時間前にあなたに非常に似たコードの一部を使用しますが、セッションは、ユーザー名(変更し、これを探していたssh_tmux$USER
Iacchus

4
vsについても役立つコメントについては、moneytooの回答を参照してください。$SSH_TTY$SSH_CONNECTION
タオ氏2018

2
少し混乱している場合は、はるかに短いものtmux new-session -A -s ssh_tmuxを置き換えるために使用できます。セッションがすでに存在する場合は、tmuxにセッションをアタッチするように指示しますtmux attach-session -t ssh_tmux || tmux new-session -s ssh_tmux-A
Gradient

3
「SCP」を壊す避けるために、あなたも、これは対話的なシェルであるかどうかを確認する必要があるでしょう:if [[ -n "$PS1" ]] && [[ -z "$TMUX" ]] && [[ -n "$SSH_CONNECTION" ]];
janfrode

3
@janfrodeは依存せず$PS1[[ $- == *i* ]]代わりに使用します。これは、PS1がインタラクティブシェルでなくても定義される可能性があるためです。
エンリコ

56

さて、私はほとんど満足のいく解決策を見つけました。私の地元では~/.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 Forcetmuxコマンドと同等であり、必要です。)


22
お使いのバージョンがtmuxサポートしている場合は、可能であればtmux new -A foo名前が付けられた既存のセッションにアタッチするものを使用fooし、必要に応じて作成することを検討してください。これにより、関数を単純化できます/usr/bin/ssh -t "$@" tmux new -A(必ず引用して$@ください!)。
chepner 2014

2
注:定期的に接続する一部のマシンにtmuxがインストールされていない場合は、通常どおりfunction ssht使用し続けることができるように、などと言ってくださいssh。それ以外の場合は、/usr/bin/sshtmuxのないマシンに接続するときはいつでもコマンドプロンプトで入力してください:)
Alex Ryan

1
怠け者の場合は、sshtを使用してリモートtmuxセッションに接続できます。OS Xユーザーはbrew経由でタップでき、LinuxユーザーはこのMakefileを使用してfpm経由でパッケージを作成するか、単ににコピーできます。ssht~/bin
brejoc 2016

1
ハハいいね!このbashワンライナーをMakefileやbrewなどでGithubリポジトリ全体にラップするのは少しやり過ぎのようですが、ちょっと簡単な方がいいです!
Alex Ryan

1
解決済み:ssh -t user@hostname "LANG=$LANG tmux attach || tmux new"
alecdwm 2016

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セッションに対応する一時的なsession-idを使用する場合は、tmuxidとして使用します。

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です。
フロリアンウェンデルボーン2015

4
tmuxの新しいバージョンではtmux new-session -A、それが存在する場合はアタッチし、そうでない場合は新しいバージョンを作成することもできます。
dragon788 2017年

18

リモートマシン上のtmux3.1以降¹

あなたの地元に~/.ssh/config、put²:

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

無関係ですが、ASCII以外の文字を扱っている場合tmux -u …は、適切な環境変数が設定されていないマシンでもUnicodeサポートを明示的に有効にするために、これをに変更することをお勧めします。

リモートマシン上のtmux3.0a以前

上記とほぼ同じですが、最後の行を³に変更します。

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

¹2020-10-29の時点で、tmux3.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ます。
エリック

切断するだけです。私に関する限り、それは私が期待し、満足している行動です。
65

1
Ctrl-B D作品と比較して扱いCtrl-B Ctrl-Zます。ありがとう!
エリック

1
これは、私見、最も投票された答えでなければなりません。私はまさに(2)を探していました。
cduguet

17

@kingmeffistoからの行を使用し(その回答にコメントすることは許可されていません)、出口を追加したので、tmuxを終了するとssh接続も終了します。ただし、これによりSFTPセッションが中断されたため、の$SSH_TTY代わりにチェックする必要がありました$SSH_CONNECTION

編集4/2018:[[ $- =~ i ]]Ansibleなどのツールが機能できるようにするためのインタラクティブターミナルのテストを追加しました。

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

15

このブログ投稿で説明されているように、sshを実行してから、次の1つのコマンドで既存のtmuxセッションに接続できます。

ssh hostname -t tmux attach -t 0

1
それが私の答えです(ただしtmux attach || tmux new、接続ごとに新しいtmuxセッションが作成されないように使用しています)。トリッキーな部分は、正しいコマンドがssh -t user@host tmux attach || tmux newあり、コマンド文字列内で引数を必要とするものにエイリアスを付ける唯一の方法は、上記のように新しい関数を作成することです。
Alex Ryan

私は知っていますが、(私のような)一部の人々は関数の定義を含まないワンライナーを好むかもしれません
Fabian Pedregosa 2015

3
これは「0」と呼ばれるセッションに接続します。つまり、一般的な形式はssh [hostname] -t tmux attach -t [sessionName]
David Doria

1
これは私にとって本当にうまくいきました..これを組み合わせるとunix.stackexchange.com/a/116674 ..なので、私のパテGUIは次のようになります..imgur.com / uFhxN30。Cntrl + b + dでセッションを切断できます。非常にシンプルで便利な...
alpha_989

2

byobuはtmux / screenの便利なラッパーです。存在する場合は既存のセッションに接続するか、新しいセッションを作成します。

sshセッションを正常に再接続するautosshで使用します。断続的な接続の問題が発生した場合に強くお勧めします。

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

2

これが便利だと思うかもしれません-ループで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

2

これは、実際に優れたユーザーエクスペリエンスを生み出すものです。ターミナルを開くと(物理的にもsshも)、tmuxが自動的に起動します。一方のデバイスで作業を開始し、ターミナルを終了して、もう一方のデバイスで再開できます。すでにセッションに接続している人を検出すると、新しいセッションが作成されます。それを入れて、サーバー上のシェルに応じて、~/.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

この方法では、sshセッションが切断された場合に、古いtmuxインスタンスに再接続できます。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

0

リモートサーバーの下部に追加~/.bashrc(あるいはその/etc/.bashrc.shared(1))

# ======================== PUT THIS LAST IN .BASHRC ==========================
# --- If we're run by SSH, then auto start `tmux` and possibly re-attach user.
#       $-         interactive only via current option flags
#       -z $TMUX   no tmux nesting
#       $SSH_TTY   SSH must be running, and in a shell
#
if [[ $- == *i* ]] && [[ -z "$TMUX" ]] && [[ -n "$SSH_TTY" ]];  then
  tmux attach-session -t "$USER"  || tmux new-session -s "$USER" && exit
fi

上記の多くの良いヒントがここ組み合わされています。たとえば$-$SSH_TTYより良いと思います。

そして、私はこの老人がそれを調べなくても何が起こっているのかを思い出すのを助けるためにいくつかのコメントを追加するのが好きです。

そして最後に、私は最後に私exitが終わったときにきれいに家に帰るのが好きです。

みんな、ありがとう。


色付き、さまざまなエイリアス、関数、パス拡張など、両方で使用される一般的なもののために、/etc/.bashrc.sharedユーザーとルートの両方の最後に共有をソースすることに注意してください。つまり、root /.bashrcにもユーザーにも冗長なコードは必要ありません。 /.bashrc。.bashrcls

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.