如何在SSH会话上自动启动tmux?

问题描述 投票:53回答:9

我有十台左右的服务器,我定期用SSH连接。每个都在我的本地计算机的~/.ssh/config文件中有一个条目。

为了避免在我的Internet连接不可避免地丢失时失去对正在运行的进程的控制,我总是在tmux会话中工作。我希望有一种方法可以在每次启动SSH连接时自动连接tmux,所以在SSH输入后我不必总是输入tmux attach || tmux new

不幸的是,这并不像我原先希望的那么简单。

  • 我不想在服务器上向~/.bashrc添加任何命令,因为我只想要它用于SSH会话,而不是本地会话。
  • tmux attach || tmux new添加到服务器上的~/.ssh/rc只会导致连接后抛出错误not a terminal,即使在本地SSH配置文件中将RequestTTY force选项添加到该服务器的行中也是如此。
ssh tmux
9个回答
61
投票

服务器端配置:

要在通常通过SSH(并且只有SSH)登录时自动启动远程服务器上的tmux,请相应地编辑远程服务器上用户或root(或两者)的~/.bashrc

if [[ -z "$TMUX" ]] && [ "$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


42
投票

好吧,我找到了一个满意的解决方案。在我当地的~/.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命令是必需的。)


13
投票

我使用了来自@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

10
投票

连接:

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会话相对应的临时会话ID,请使用tmux id:

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

9
投票

this blog post中所述,您可以使用单个命令ssh然后附加到现有的tmux会话:

ssh hostname -t tmux attach -t 0

3
投票

恕我直言,答案列表中缺少两种可能的解决方案:

  1. 使用主机的~/.ssh/authorized_keys文件:
command="tmux attach-session -t mysession || tmux new-session -s mysession" ssh-ed25519 AAAAfoo23bar45foo23bar45foo23bar45foo23bar45foo23bar45foo23bar45foo23bar45 user@client

当然,这将由安装了相应私钥的所有客户端工作,这可能是上行或下行,具体取决于。存在一些风险,如果出现任何问题,可能无法再进入服务器。

  1. 使用客户端的~/.ssh/config file,@op已经在使用了:
Host myhost
  Hostname host
  User user
  RequestTTY yes # tmux needs a tty and won't work without one!
                 # sometimes requires "force" instead of "yes".
  RemoteCommand tmux attach-session -t mysession || tmux new-session -s mysession

考虑到选项(1)的风险,这可能是更好的解决方案。如果有任何问题,只需要注释掉这两行。


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

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在list-clients上失败的错误。

© www.soinside.com 2019 - 2024. All rights reserved.