我有十台左右的服务器,我定期用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(并且只有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
。
好吧,我找到了一个满意的解决方案。在我当地的~/.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命令是必需的。)
我使用了来自@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
连接:
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"
如this blog post中所述,您可以使用单个命令ssh然后附加到现有的tmux会话:
ssh hostname -t tmux attach -t 0
恕我直言,答案列表中缺少两种可能的解决方案:
~/.ssh/authorized_keys
文件:command="tmux attach-session -t mysession || tmux new-session -s mysession" ssh-ed25519 AAAAfoo23bar45foo23bar45foo23bar45foo23bar45foo23bar45foo23bar45foo23bar45 user@client
当然,这将由安装了相应私钥的所有客户端工作,这可能是上行或下行,具体取决于。存在一些风险,如果出现任何问题,可能无法再进入服务器。
~/.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)的风险,这可能是更好的解决方案。如果有任何问题,只需要注释掉这两行。
您可能会发现这很有用 - 在循环中使用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
我知道我正在恢复旧的线程,但我已经在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上失败的错误。