¿Cómo iniciar automáticamente tmux en una sesión SSH?

92

Tengo unos diez servidores a los que me conecto con SSH de forma regular. Cada uno tiene una entrada en mi computadora local~/.ssh/config archivo de .

Para evitar perder el control de mi proceso de ejecución cuando mi conexión a Internet inevitablemente se cae, siempre trabajo dentro de una tmuxsesión. Me gustaría una forma de que tmux se conecte automáticamente cada vez que se inicia una conexión SSH, por lo que no tengo que escribir siempre tmux attach || tmux newdespués de ingresar por SSH.

Desafortunadamente, esto no está resultando ser tan simple como esperaba originalmente.

  • No quiero agregar ningún comando a los ~/.bashrcservidores porque solo lo quiero para sesiones SSH, no sesiones locales.
  • Agregar tmux attach || tmux newa los ~/.ssh/rcservidores simplemente da como resultado que se arroje el error not a terminaldespués de la conexión, incluso cuando la RequestTTY forceopción se agrega a la línea para ese servidor en mi archivo de configuración SSH local.
Alex Ryan
fuente
1
Como esta sigue siendo una pregunta popular y menciona específicamente ~/.ssh/config: la mayoría de los que vienen aquí probablemente no estén buscando ninguna de las primeras cinco respuestas, sino la sexta ( stackoverflow.com/a/52838493/5354137 ). Con cualquier tmuxversión razonablemente reciente , esa también es la forma más sensata de hacer las cosas.
Sesenta

Respuestas:

90

Configuración del lado del servidor:

Para iniciar automáticamente tmux en su servidor remoto cuando normalmente inicia sesión a través de SSH (y solo SSH), edite el ~/.bashrcde su usuario o raíz (o ambos) en el servidor remoto en consecuencia:

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

Este comando crea una sesión tmux llamada ssh_tmux si no existe ninguna, o se vuelve a conectar a una sesión ya existente con ese nombre. En caso de que su conexión se interrumpa o cuando haya olvidado una sesión hace semanas, cada inicio de sesión SSH lo regresa automáticamente a la sesión tmux-ssh que dejó atrás.

Conéctese desde su cliente:

Nada especial, solo ssh user@hostname.

reymeffisto
fuente
4
Estaba buscando esto, también usé un código muy similar al tuyo hace algún tiempo, pero la sesión era el nombre de usuario (cambiando ssh_tmuxa $USER)
Iacchus
3
Vea la respuesta de moneytoo para un comentario útil sobre $SSH_TTYvs $SSH_CONNECTIONtambién.
Mr. Tao
2
puede usar tmux new-session -A -s ssh_tmuxpara reemplazar tmux attach-session -t ssh_tmux || tmux new-session -s ssh_tmuxmucho más corto, si es un poco más confuso, -Ale dice a tmux que adjunte la sesión si ya existe
Gradiente
3
Para evitar romper "scp", también debe verificar si se trata de un shell interactivo:if [[ -n "$PS1" ]] && [[ -z "$TMUX" ]] && [[ -n "$SSH_CONNECTION" ]];
janfrode
2
@janfrode no confíe en $PS1, use [[ $- == *i* ]]en su lugar, ya que PS1 puede definirse incluso cuando no es un shell interactivo.
Enrico
53

Muy bien, encontré una solución bastante satisfactoria. En mi local ~/.bashrc, escribí una función:

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

que básicamente sobrescribe la función de terminal ssh para llamar al programa ssh incorporado con los argumentos dados, seguido de "tmux attach || tmux new".

( $@Denota todos los argumentos proporcionados en la línea de comando, por ssh -p 123 user@hostnamelo que se expandirá a ssh -t -p 123 user@hostname "tmux attach || tmux new")

(Los -t argumento es equivalente RequestTTY Forcey necesario para el comando tmux).

Alex Ryan
fuente
22
Si su versión de la tmuxadmite, considere usar la tmux new -A fooque se adjuntará a una sesión existente nombrada foosi es posible, creándola si es necesario. Esto le permite simplificar su función /usr/bin/ssh -t "$@" tmux new -A(¡y asegúrese de citar $@!).
chepner
1
Nota: si algunas de las máquinas a las que se conecta regularmente no tienen tmux instalado, es posible que desee decir function sshto algo similar para que pueda continuar usándolo sshnormalmente. De lo contrario, simplemente escriba /usr/bin/sshen el símbolo del sistema cada vez que se conecte a una máquina sin tmux :)
Alex Ryan
1
Si es vago, puede usar ssht para conectarse a sus sesiones remotas de tmux. Usuarios de OS X pueden tocarlo a través de cerveza y los usuarios de Linux pueden crear un paquete a través de FPM con este Makefile o simplemente copiar sshta ~/bin.
Brejoc
1
¡Jaja bueno! Me parece un poco exagerado envolver este bash de una sola línea en un repositorio completo de Github con Makefiles y brew y demás, pero bueno, ¡cuanto más fácil, mejor!
Alex Ryan
1
Resuelto:ssh -t user@hostname "LANG=$LANG tmux attach || tmux new"
alecdwm
23

Conectar:

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

Durante la sesión:

Úselo Ctrl+dpara finalizar la sesión (la ventana tmux se cierra) o Ctrl+b dpara desconectarse temporalmente de la sesión y conectarse nuevamente más tarde.

¡Recuerda! Si su servidor se reinicia, la sesión se pierde!

Cuando esté dentro de tmux en cualquier momento, puede usar Ctrl+b spara ver la lista de sesiones y cambiar la actual a otra.

Arregle su .bashrc:

Te recomiendo definir la función universal en tu .bashrc:

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

Utiliza el 22puerto por defecto. Defina también sus alias de conexión rápida:

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

Iniciar sesión sin contraseña:

Y si no desea escribir la contraseña cada vez que genere .sshclaves para iniciar sesión automáticamente :

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

Pon tu clave pública en el host remoto:

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

Consejos adicionales:

Si desea utilizar un ID de sesión temporal que se corresponda con una sesión de bash local, utilice como ID de tmux :

SID=$USER-$BASHPID
ssh user@host -t "tmux new-session -s $SID || tmux attach-session -t $SID"
DenisKolodin
fuente
1
Un buen truco para evitar que ||en algunos casos de uso es incluir new-sessionen .tmux.confy sólo tiene que utilizar siempre tmux a -t 0.
Florian Wendelborn
4
En las versiones más recientes de tmux, también puede usar el tmux new-session -Aque se adjuntará si existe, de lo contrario creará uno nuevo.
dragon788
15

Usé líneas de @kingmeffisto (no puedo comentar esa respuesta) y agregué una salida para que la terminación de tmux también termine la conexión ssh. Sin embargo, esto rompió las sesiones SFTP, por lo que tuve que verificar en $SSH_TTYlugar de $SSH_CONNECTION.

EDITAR 4/2018: Prueba agregada para terminal interactivo a través de [[ $- =~ i ]]para permitir que funcionen herramientas como Ansible.

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

Como se describe en esta publicación de blog , puede ssh y luego adjuntarlo a una sesión tmux existente con un solo comando:

ssh hostname -t tmux attach -t 0
Fabián Pedregosa
fuente
Eso es lo que hace mi respuesta (aunque lo uso tmux attach || tmux newpara que no se cree una nueva sesión tmux para cada conexión). La parte complicada es que el comando correcto es ssh -t user@host tmux attach || tmux newy la única forma de alias algo que necesita un argumento dentro de la cadena de comandos es crear una nueva función, como hice anteriormente.
Alex Ryan
Lo sé, pero algunas personas (como yo) podrían preferir una frase de una sola línea que no implique definir una función
Fabian Pedregosa
3
Esto se conecta a una sesión llamada '0'. Es decir, la forma general esssh [hostname] -t tmux attach -t [sessionName]
David Doria
1
Esto funcionó muy bien para mí .. Combinado esto unix.stackexchange.com/a/116674 .. así que ahora mi GUI de masilla se ve así .. imgur.com/uFhxN30 . Puedo desconectar las sesiones con Cntrl + b + d. Muy simple y conveniente ..
alpha_989
14

tmux 3.1 o más reciente¹ en la máquina remota

En su local ~/.ssh/config, ponga²:

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

No relacionado, pero si está tratando con caracteres que no son ASCII, le recomiendo cambiar eso a tmux -u … para habilitar explícitamente el soporte Unicode incluso en máquinas que no tienen configuradas las variables de entorno adecuadas.

tmux 3.0a o anterior en la máquina remota

Casi igual que el anterior, pero cambia la última línea a³:

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

¹ A partir del 2020-10-29, la lista de distribuciones que se envían con tmux 3.1 o posterior es bastante larga.

² newes la abreviatura de new-session.

³ ates la abreviatura de attach-session.


Método alternativo usando el authorized_keysarchivo del control remoto :

Si prefiere no tener un ~/.ssh/configarchivo por cualquier motivo, o si desea que la máquina remota obligue a la máquina que se conecta a conectarse o abrir la sesión, agregue esto a su control remoto ~/.ssh/authorized_keys:

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

Esto, por supuesto, funcionará desde todos los clientes que tengan instalada la clave privada correspondiente, lo que podría ser una ventaja o una desventaja, según lo que desee. Existe el riesgo de que, en caso de que algo salga mal, ya no sea posible conectarse.

Sesenta y cinco
fuente
¿Por qué en tmux atlugar de tmux a? También sería prudente usar una sesión con nombre para esto o tmux se adjuntaría a sesiones existentes "aleatorias" al iniciar sesión en el host.
Eric
¿Cómo suspendes la sesión tmux? ssh entra en un estado de kindda limbo después de golpear Ctrl+A Ctrl+Z.
Eric
Simplemente se desconecta. En lo que a mí respecta, ese es el comportamiento que esperaría y con el que estoy feliz.
Sesenta
1
Ctrl-B Dfunciona tratar en comparación con Ctrl-B Ctrl-Z. ¡Gracias!
Eric
1
Esta debería ser, en mi humilde opinión, la respuesta más votada. Estaba buscando exactamente (2).
cduguet
1

byobu es un contenedor muy útil para tmux / screen. Se conecta a una sesión existente si está presente o crea una nueva.

Lo uso con autossh que reconecta con gracia la sesión ssh. Muy recomendable en caso de problemas de conectividad intermitentes.

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'
}
Sandeep
fuente
1

Puede que le resulte útil: utiliza ssh en un bucle y se vuelve a conectar o se conecta a una sesión tmux existente para que tenga una forma agradable, fácil y confiable de volver a conectarse después de una interrupción de la red

#!/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
Neil McGill
fuente
1

Este es el que realmente crea una gran experiencia de usuario. Automáticamente inicia tmux cada vez que abre la terminal (tanto físicamente como ssh). Puede comenzar su trabajo en un dispositivo, salir de la terminal y reanudar en el otro. Si detecta a alguien ya adjunto a la sesión, creará una nueva sesión. Ponlo en el servidor , dependiendo de tu shell ~/.zshrco ~/.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
Stanislaw Baranski
fuente
0

Sé que estoy reviviendo un hilo antiguo, pero he trabajado un poco en la solución bashrc y creo que tiene algún uso:

#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

Hay un límite de 10 (11) sesiones por ahora; no quería matar mi servidor con un bucle infinito en bashrc. Parece funcionar de manera bastante confiable, aparte del error de tmux fallando en la lista de clientes si la sesión no existe.

Brydon Gibson
fuente
0

Esta forma le permite volver a conectarse a una instancia tmux antigua si su sesión ssh cae. El execguarda un tenedor, por supuesto.

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
ericcurtin
fuente