Exécuter des commandes à distance, en se déconnectant complètement de la connexion ssh

48

J'ai 2 ordinateurs localpcet remoteserver.

J'ai besoin localpcd'exécuter des commandes sur remoteserver. Une des choses à faire est de lancer un script de sauvegarde qui dure plusieurs heures. Je voudrais que la commande localpc“tire” puis soit totalement indépendante remoteserver, comme localpcjamais auparavant.

C'est ce que j'ai fait jusqu'à présent:

remoteserver contient a le script:

/root/backup.sh

localpc est prévu pour exécuter ceci:

ssh root@remoteserver 'nohup /root/backup.sh' &

Est-ce que je le fais de la bonne façon? Y a-t-il une meilleure manière de faire cela? Est-ce que je vais avoir du mal à le faire de cette façon?

LVLAaron
la source
stackoverflow.com/questions/19996089/… et stackoverflow.com/questions/29142/… fournissent un certain nombre d'approches utiles pour résoudre ce problème en n'utilisant pas screen / tmux, etc.
Paul

Réponses:

47

Vous devriez probablement utiliser screensur l'hôte distant, pour avoir une vraie commande détachée:

ssh root@remoteserver screen -d -m ./script
enzotib
la source
J'aime cette idée. Une fois le script terminé, l'écran fonctionnera toujours ... et je devrais me reconnecter à celui-ci la prochaine fois que je voulais l'exécuter, n'est-ce pas?
LVLAaron le
@AaronJAnderson: non, étant donné que la commande n'est pas un shell, lorsqu'elle se termine, cette session d'écran se termine également.
enzotib
52

Proche, mais pas exactement.

Indépendamment de tout terminal

ssh root@remoteserver '/root/backup.sh </dev/null >/var/log/root-backup.log 2>&1 &'

Vous devez fermer tous les descripteurs de fichier connectés au socket ssh, car la session ssh ne se fermera pas tant qu'un processus distant a ouvert le socket. Si la sortie du script ne vous intéresse pas (probablement parce que le script lui-même s'occupe de l'écriture dans un fichier journal), redirigez-le vers /dev/null(mais notez que cela masquera des erreurs telles que l'impossibilité de démarrer le script).

L'utilisation nohupn'a aucun effet utile ici. nohupveille à ce que le programme qu'il exécute ne reçoive pas de signal HUP si le terminal de contrôle du programme disparaît, mais ici, il n'y a pas de terminal en premier lieu, donc rien ne va envoyer un SIGHUP au processus de manière inattendue. De plus, nohupredirige la sortie standard et l'erreur standard (mais pas l'entrée standard) vers un fichier, mais uniquement s'ils sont connectés à un terminal, ce qu'ils ne sont pas encore.

Se détacher d'un terminal

 aaron@localpc$ ssh root@remoteserver
 root@remoteserver# nohup /root/backup.sh </dev/null &
 nohup: appending output to `nohup.out'
 [1] 12345
 root@remoteserver# exit
 aaron@localpc$ 

Permet nohupde détacher le script de son terminal de contrôle afin qu’il ne reçoive pas de SIGHUP lorsque le terminal disparaît. nohupredirige également la sortie standard et l'erreur standard du script vers un fichier appelé nohup.outs'il est connecté au terminal; vous devez vous occuper de l'entrée standard vous-même.

Garder un terminal distant

Si vous souhaitez conserver la commande en cours d'exécution dans un terminal distant sans la connecter à la session SSH, exécutez-la dans un multiplexeur de terminal tel que Screen ou Tmux .

ssh root@remoteserver 'screen -S backup -d -m /root/backup.sh'

Vous pouvez vous reconnecter ultérieurement au terminal sur lequel le script est exécuté en appelant en screen -S backup -rdtant que root sur cette machine.

Automatisation d'une commande à distance

Pour une sécurité légèrement meilleure, n'ouvrez pas trop souvent les connexions root directes à distance. Créez une paire de clés spéciale et donnez-lui une commande forcée /root/.ssh/authorized_keys. Le contenu du fichier de clé publique est AAAA…== [email protected]; ajoutez une liste d'options séparées par des virgules, command="…"indiquant notamment que la clé ne peut être utilisée que pour exécuter cette commande spécifique. Assurez-vous de garder les options et la clé sur une seule ligne.

command="/root/backup.sh </dev/null >/dev/null 2>/dev/null &",no-port-forwarding,no-agent-forwarding,no-x11-forwarding,no-pty,no-user-rc AAAA…== [email protected]
Gilles, arrête de faire le mal
la source
J'ai essayé la première commande que vous avez énumérée. Il n’a pas d’arrière-plan sur la boîte qui a exécuté la commande. Le curseur est juste assis là et attend la fin ... c'est peut-être un bug?
LVLAaron le
Vous devrez peut-être rediriger stdin vers / dev / null sur le système distant. C'est peut-être pour ça que ssh ne s'en va pas.
KeithB
J'ajouterais l' -foption permettant à ssh de se placer sur "l'arrière-plan" (c'est-à-dire les connexions terminées et fermées) du côté local. Cela fonctionnera en conjonction avec le &. nohupest facultatif dans ce cas, mais vous pouvez envisager d’utiliser setsidplutôt.
Alexios
@ KeithB La redirection de stdin en fait partie, mais j'ai également besoin de rediriger stdout et stderr: nohup ne le fera pas ici car ce ne sont pas des terminaux, et en fait nohup n'est pas utile ici.
Gilles 'SO- arrête d'être méchant' le
1
@erikbwork Veuillez noter que je n'ai absolument aucune idée de ces choses, mais après la discussion et les commentaires: Gilles n'utilise pas l'option -t dans ses commandes, donc aucun pseudo terminal ne sera établi, ni sur le client ni sur le serveur. côté. Par conséquent, aucun HUP ne sera envoyé.
Binarus
12

La recette standard pour exécuter une commande à distance à partir d'une connexion à distance telle que SSH est la suivante:

nohup command </dev/null >command.log 2>&1 &

Si commandun script shell prend en charge la journalisation dans un fichier, vous pouvez le remplacer command.logpar /dev/null. Une fois que vous avez commencé, déconnectez-vous immédiatement.

Vous avez besoin de tout sur cette ligne.

nohup indique au shell de ne pas perturber le processus si la session de connexion est déconnectée.

</dev/null lui dit de ne jamais attendre l'entrée

>command.log lui dit d'envoyer des messages à ce fichier journal nommé

2>&1lui dit d’envoyer des messages stderr dans le même fichier journal. Dans certains cas, il est préférable d’avoir deux fichiers, le second pour collecter les messages d’erreur et le premier pour collecter les messages d’activité normale. Cela peut faciliter la vérification du bon fonctionnement de tout.

& lui dit de détacher ce processus et de l'exécuter en arrière-plan en tant que processus démon.

Michael Dillon
la source
10

Ce fil était très utile mais ma solution devait être un peu différente.

Je n'aime pas la solution d'écran car elle laisse un processus d'écran en cours d'exécution dont je n'ai pas besoin. Les redirections et nohups utilisés comme ceci:

ssh root@remoteserver '/root/backup.sh </dev/null >/var/log/root-backup.log 2>&1 &'

ne fonctionnaient PAS pour moi lorsqu’ils étaient utilisés avec la commande ssh.

J'ai créé un script wrapper sur la machine distante qui exécute le script proprement dit. Le script wrapper définit la redirection et nohup. Quelque chose comme ça:

backupwrapper.sh:
nohup backup.sh > /dev/null 2>&1 &

Ensuite, sur mon ordinateur client, je lance (ne remarque aucune redirection):

# ssh remotemachine "backupwrapper.sh"
#

La commande ssh retourne immédiatement, la connexion est interrompue et le script est en cours d'exécution.

rui
la source
6

Comme Nils le dit , permettre à la racine de se connecter via ssh constitue un risque pour la sécurité. Et je déconseille d'exécuter un travail important sur une machine sans journal. Si quelque chose ne va pas, vous souhaiterez des messages de dépannage. Il y a d'autres réponses qui vous montrent comment faire cela. Mais voici comment je recommande d'accomplir exactement ce que vous avez demandé. Tout est intégré dans sh (1). Pas besoin d'écran GNU (bien que je pense que c'est une solution intelligente). Append cette chaîne à votre commande: >&- 2>&- <&- &. >&-signifie fermer stdout. 2>&-signifie proche stderr. <&-signifie proche stdin. &signifie exécuté en arrière-plan, p.ex.

$ ssh myhost 'sleep 30 >&- 2>&- <&- &'
# ssh returns right away, and your sleep job is running remotely
$
tbc0
la source
0

Vous devriez mettre en arrière-plan la commande à distance remoteserver. La façon dont vous le ferez servira de base à la commande ssh localpc.

En dehors de cela, il est déconseillé d'autoriser root-ssh.

Donc, configurez sur remoteserver: Une ligne sudoers qui s’exécutera en /root/backup.shtant que root par utilisateur backup.

Vous pouvez créer cet utilisateur sans "bon" mot de passe.

Mettez la commande en sudo /root/backup.sh &tant que commande dans ~backup/.ssh/authorized_keys- avec la clé publique de localpc(celui qui déclenche ce script).

Nils
la source
-1
#screen -d -m -S BACKUP ssh root@remoteserver /root/backup.sh
Killinks
la source
2
Ce n'est pas très utile: si la connexion SSH meurt, les commandes stdout et stderr du script seront fermées, ce qui peut poser problème. L'écran devrait être en cours d'exécution sur la machine distante (comme dans la réponse de enzotib ).
Gilles 'SO- arrête d'être méchant' le