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

时间:2014-12-23 02:18:18

标签: ssh tmux

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

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

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

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

14 个答案:

答案 0 :(得分:56)

服务器端配置:

要在通常通过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

答案 1 :(得分:40)

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

答案 2 :(得分:11)

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

答案 3 :(得分:9)

连接

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

会话期间:

从会话中使用Ctrl+d 完成会话(tmux窗口关闭)或Ctrl+b d临时分离,然后再次连接到该会话。< / p>

  

请记住!如果您的服务器重新启动会话丢失了!

当您在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"

答案 4 :(得分:8)

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

ssh hostname -t tmux attach -t 0

答案 5 :(得分:2)

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

  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)的风险,这可能是更好的解决方案。如有任何问题,只需将这两行注释掉。

答案 6 :(得分: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

答案 7 :(得分: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'
}

答案 8 :(得分: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

答案 9 :(得分:1)

我有以下解决方案,可让您连接两台 SSH 主机:一台带 tmux,一台不带:

ID    
1
2
3
4
5

答案 10 :(得分: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在列表客户端上失败的错误之外。

答案 11 :(得分: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

答案 12 :(得分: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的末尾都提供了共享的.bashrc,用于两者中使用的常见内容,例如彩色{ 1}},各种别名,函数和路径扩展,即,我不需要root / .bashrc或user / .bashrc中的冗余代码。

答案 13 :(得分:0)

This guys script works great。只需将 bashrc-tmux 文件复制到 ~/.bashrc-tmux 并在 PS1 检查部分之后从 ~/.bashrc 中获取它。