Comment démarrer automatiquement tmux sur une session SSH?


92

J'ai une dizaine de serveurs auxquels je me connecte régulièrement avec SSH. Chacun a une entrée dans le ~/.ssh/configfichier de mon ordinateur local .

Pour éviter de perdre le contrôle de mon processus en cours lorsque ma connexion Internet tombe inévitablement, je travaille toujours dans une tmuxsession. Je voudrais un moyen pour que tmux se connecte automatiquement à chaque fois qu'une connexion SSH est démarrée, donc je n'ai pas à toujours taper tmux attach || tmux newaprès que je sois connecté en SSH.

Malheureusement, ce n'est pas aussi simple que je l'espérais au départ.

  • Je ne veux pas ajouter de commandes au ~/.bashrcsur les serveurs car je le veux uniquement pour les sessions SSH, pas pour les sessions locales.
  • L'ajout tmux attach || tmux newà ~/.ssh/rcsur les serveurs entraîne simplement l'erreur not a terminalgénérée après la connexion, même lorsque l' RequestTTY forceoption est ajoutée à la ligne pour ce serveur dans mon fichier de configuration SSH local.

1
Comme cela continue d'être une question populaire et le mentionne spécifiquement ~/.ssh/config: la plupart d'entre vous qui viennent ici ne recherchent probablement aucune des cinq premières réponses, mais la sixième ( stackoverflow.com/a/52838493/5354137 ). Avec toute tmuxversion raisonnablement récente , c'est aussi la façon la plus sensée de faire les choses.
Sixtyfive

Réponses:


90

Configuration côté serveur:

Pour démarrer automatiquement tmux sur votre serveur distant lorsque vous vous connectez normalement via SSH (et uniquement SSH), modifiez le ~/.bashrcde votre utilisateur ou root (ou les deux) sur le serveur distant en conséquence:

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

Cette commande crée une session tmux appelée ssh_tmuxs'il n'en existe pas, ou se rattache à une session déjà existante avec ce nom. Si votre connexion est interrompue ou si vous avez oublié une session il y a des semaines, chaque connexion SSH vous ramène automatiquement à la session tmux-ssh que vous avez laissée.

Connectez-vous depuis votre client:

Rien de spécial, juste ssh user@hostname.


4
Je cherchais cela, j'ai également utilisé un morceau de code très similaire au vôtre il y a quelque temps, mais la session était le nom d'utilisateur (changeant ssh_tmuxen $USER)
Iacchus

3
Voir la réponse de moneytoo pour des commentaires utiles sur $SSH_TTYvs $SSH_CONNECTIONaussi.
M. Tao

2
vous pouvez utiliser tmux new-session -A -s ssh_tmuxpour remplacer tmux attach-session -t ssh_tmux || tmux new-session -s ssh_tmuxbeaucoup plus court, si un peu plus déroutant, -Adit à tmux de joindre la session si elle existe déjà
Gradient

3
Pour éviter de casser "scp", vous devez également vérifier s'il s'agit d'un shell interactif:if [[ -n "$PS1" ]] && [[ -z "$TMUX" ]] && [[ -n "$SSH_CONNECTION" ]];
janfrode

2
@janfrode ne s'appuie pas sur $PS1, utilisez [[ $- == *i* ]]plutôt, car PS1 peut être défini même s'il ne s'agit pas d'un shell interactif.
Enrico

53

D'accord, j'ai trouvé une solution plutôt satisfaisante. Dans ma section locale ~/.bashrc, j'ai écrit une fonction:

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

qui écrase fondamentalement la fonction de terminal ssh pour appeler le programme ssh intégré avec les arguments donnés, suivis de "tmux attach || tmux new".

(Le $@désigne tous les arguments fournis sur la ligne de commande, il ssh -p 123 user@hostnamesera donc développé en ssh -t -p 123 user@hostname "tmux attach || tmux new")

(L' -targument est équivalent à RequestTTY Forceet est nécessaire pour la commande tmux.)


22
Si votre version de le tmuxprend en charge, envisagez d'utiliser tmux new -A fooqui s'attachera à une session existante nommée foosi possible, en la créant si nécessaire. Cela vous permet de simplifier votre fonction à /usr/bin/ssh -t "$@" tmux new -A(et assurez-vous de citer $@!).
chepner

1
Remarque: si certaines des machines auxquelles vous vous connectez régulièrement n'ont pas installé tmux, vous voudrez peut-être dire function sshtou autre pour pouvoir continuer à utiliser sshnormalement. Sinon, tapez simplement /usr/bin/sshà l'invite de commande chaque fois que vous vous connectez à une machine sans tmux :)
Alex Ryan

1
Si vous êtes paresseux, vous pouvez simplement utiliser ssht pour vous connecter à vos sessions tmux distantes. Les utilisateurs d'OS X peuvent le taper via brew et les utilisateurs de Linux peuvent créer un package via fpm avec ce Makefile ou simplement copier sshtvers ~/bin.
brejoc

1
Haha gentil! Cela me semble un peu exagéré d'envelopper cette bash one-liner dans un repo Github entier avec Makefiles et brasser et ainsi de suite, plus c'est facile, mieux c'est!
Alex Ryan

1
Résolu:ssh -t user@hostname "LANG=$LANG tmux attach || tmux new"
alecdwm

23

Relier:

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

Pendant la session:

Utilisez Ctrl+dpour terminer la session (la fenêtre tmux se ferme) ou Ctrl+b dpour se détacher temporairement de la session et s'y reconnecter plus tard.

Rappelles toi! Si votre serveur a redémarré la session perdue!

Lorsque vous êtes dans tmux à tout moment, vous pouvez utiliser Ctrl+b spour voir la liste des sessions et passer à une autre.

Réparez votre .bashrc:

Je vous recommande de définir la fonction universelle dans votre .bashrc:

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

Il utilise le 22port par défaut. Définissez également vos alias de connexion rapide:

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

Connexion sans mot de passe:

Et si vous ne voulez pas saisir de mot de passe à chaque fois, générez des .sshclés pour vous connecter automatiquement :

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

Mettez votre clé publique sur l'hôte distant:

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

Conseils supplémentaires:

Si vous souhaitez utiliser un identifiant de session temporaire qui correspond à une session bash locale, utilisez comme identifiant tmux :

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

1
Une astuce pour éviter que ||est d'inclure dans certains cas d' utilisation new-sessiondans .tmux.confet il suffit d' utiliser toujours tmux a -t 0.
Florian Wendelborn

4
Dans les versions plus récentes de tmux, vous pouvez également utiliser tmux new-session -Aqui s'attachera s'il existe, sinon il en créera un nouveau.
dragon788

15

J'ai utilisé des lignes de @kingmeffisto (je ne suis pas autorisé à commenter cette réponse) et j'ai ajouté une sortie afin de terminer tmux met également fin à la connexion ssh. Cela a cependant cassé les sessions SFTP, j'ai donc dû vérifier au $SSH_TTYlieu de $SSH_CONNECTION.

EDIT 4/2018: Ajout d'un test pour le terminal interactif via [[ $- =~ i ]]pour permettre à des outils comme Ansible de fonctionner.

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

14

Comme décrit dans cet article de blog, vous pouvez ssh, puis vous attacher à une session tmux existante avec une seule commande:

ssh hostname -t tmux attach -t 0

C'est ce que fait ma réponse (bien que j'utilise tmux attach || tmux newpour qu'une nouvelle session tmux ne soit pas créée pour chaque connexion). La partie délicate est que la commande correcte est ssh -t user@host tmux attach || tmux newet la seule façon d'aliaser quelque chose qui nécessite un argument dans la chaîne de commande est de créer une nouvelle fonction, comme je l'ai fait ci-dessus.
Alex Ryan

Je sais, mais certaines personnes (comme moi) pourraient préférer un one-liner qui n'implique pas de définir une fonction
Fabian Pedregosa

3
Cela se connecte à une session appelée «0». Autrement dit, la forme générale estssh [hostname] -t tmux attach -t [sessionName]
David Doria

1
Cela a très bien fonctionné pour moi .. Combiné, cela sera unix.stackexchange.com/a/116674 .. alors maintenant mon interface graphique mastic ressemble à ceci .. imgur.com/uFhxN30 . Je peux déconnecter les sessions avec Cntrl + b + d. Très simple et pratique ..
alpha_989

14

tmux 3.1 ou plus récent¹ sur la machine distante

Dans votre local ~/.ssh/config, mettez²:

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

Indépendant, mais si vous avez affaire à des caractères non ASCII, je vous recommande de le changer tmux -u …pour activer explicitement le support Unicode, même sur des machines qui n'ont pas les variables d'environnement appropriées.

tmux 3.0a ou plus ancien sur la machine distante

Presque la même chose que ci-dessus, mais remplacez la dernière ligne par³:

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

¹ À partir du 2020-10-29, la liste des distributions livrées avec tmux 3.1 ou plus récent est déjà assez longue.

² newest l'abréviation de new-session.

³ atest l'abréviation de attach-session.


Méthode alternative utilisant le authorized_keysfichier de la télécommande :

Si vous préférez ne pas avoir de ~/.ssh/configfichier pour une raison quelconque, ou si vous souhaitez que la machine distante force la machine connectée à se connecter / ouvrir la session, ajoutez ceci à votre télécommande ~/.ssh/authorized_keys:

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

Cela fonctionnera bien sûr à partir de tous les clients ayant la clé privée correspondante installée, ce qui pourrait être un inconvénient ou un inconvénient, selon ce que vous voulez. Il y a un risque que, en cas de problème, il ne soit plus possible de se connecter.


pourquoi tmux atau lieu de tmux a? De plus, il serait sage d'utiliser une session nommée pour cela ou tmux s'attacherait à des sessions existantes "aléatoires" lors de la connexion à l'hôte.
Eric

Comment suspendre la session tmux? ssh entre dans l'état des limbes kindda après avoir frappé Ctrl+A Ctrl+Z.
Eric le

Il se déconnecte simplement. En ce qui me concerne, c'est le comportement auquel je m'attendrais et je suis content.
Sixtyfive

1
Ctrl-B Dfonctionne traiter par rapport à Ctrl-B Ctrl-Z. Merci!
Eric

1
Cela devrait être, à mon humble avis, la réponse la plus votée. Je cherchais exactement (2).
cduguet

1

byobu est un joli wrapper utile pour tmux / screen. Se connecte à une session existante si elle est présente ou en crée une nouvelle.

Je l'utilise avec autossh qui reconnecte gracieusement la session ssh. Fortement recommandé en cas de problèmes de connectivité intermittents.

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

Vous pourriez trouver cela utile - utilise ssh dans une boucle et se reconnecte ou se connecte à une session tmux existante afin que vous ayez un moyen fiable et simple de vous reconnecter après une panne de réseau

#!/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

1

C'est celui qui crée en fait une excellente expérience utilisateur. Il démarre automatiquement tmux chaque fois que vous ouvrez le terminal (à la fois physiquement et ssh). Vous pouvez commencer votre travail sur un appareil, quitter le terminal et reprendre sur l'autre. S'il détecte quelqu'un déjà attaché à la session, il créera une nouvelle session. Mettez-le sur le serveur , en fonction de votre shell ~/.zshrcou ~/.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

Je sais que je suis en train de relancer un ancien thread, mais j'ai travaillé sur la solution bashrc et je pense qu'elle a une certaine utilité:

#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

Il y a un plafond à 10 (11) sessions pour l'instant - je ne voulais pas tuer mon serveur avec une boucle infinie dans bashrc. Cela semble fonctionner de manière assez fiable, à part l'erreur de l'échec de tmux sur les clients de liste si la session n'existe pas.


0

Cette méthode vous permet de vous reconnecter à une ancienne instance tmux si votre session ssh tombe. Le execsauve bien sûr une fourchette.

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.