Führen Sie Remote-Befehle aus und trennen Sie sie vollständig von der SSH-Verbindung

48

Ich habe 2 Computer localpcund remoteserver.

Ich muss localpceinige Befehle ausführen remoteserver. Dazu muss unter anderem ein Sicherungsskript gestartet werden, das mehrere Stunden ausgeführt wird. Ich möchte den Befehl auf localpc"feuern" und dann völlig unabhängig weiterlaufen remoteserver, localpcals wäre er noch nie da gewesen.

Das habe ich bisher gemacht:

remoteserver enthält hat das Skript:

/root/backup.sh

localpc ist geplant, dies auszuführen:

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

Mache ich das richtig? Gibt es einen besseren Weg, dies zu tun? Werde ich auf diese Weise Probleme bekommen?

LVLAaron
quelle
stackoverflow.com/questions/19996089/… und stackoverflow.com/questions/29142/… bieten eine Reihe nützlicher Ansätze für dieses Problem, wenn screen / tmux usw. nicht verwendet wird.
Paul

Antworten:

47

Sie sollten wahrscheinlich screenauf dem Remote-Host verwenden, um einen echten getrennten Befehl zu haben:

ssh root@remoteserver screen -d -m ./script
Enzotib
quelle
Ich mag diese Idee. Wenn das Skript fertig ist, läuft der Bildschirm immer noch ... und ich müsste mich das nächste Mal irgendwie wieder damit verbinden, wenn ich es ausführen möchte, oder?
LVLAaron
@AaronJAnderson: Nein, vorausgesetzt, der Befehl ist keine Shell, wenn er beendet wird, wird auch diese Bildschirmsitzung beendet.
Enzotib
52

Nah dran, aber nicht genau.

Unabhängig von einem Terminal

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

Sie müssen alle Dateideskriptoren schließen, die mit dem ssh-Socket verbunden sind, da die ssh-Sitzung nicht geschlossen wird, solange ein Remote-Prozess den Socket geöffnet hat. Wenn Sie nicht an der Ausgabe des Skripts interessiert sind (vermutlich, weil das Skript selbst das Schreiben in eine Protokolldatei übernimmt), leiten Sie es weiter an /dev/null(beachten Sie jedoch, dass hierdurch Fehler ausgeblendet werden, z. B., dass das Skript nicht gestartet werden kann).

Die Verwendung nohuphat hier keinen nützlichen Effekt. nohupsorgt dafür, dass das Programm, das ausgeführt wird, kein HUP-Signal empfängt, wenn das steuernde Terminal des Programms verschwindet, aber hier gibt es überhaupt kein Terminal, sodass nichts aus heiterem Himmel ein SIGHUP an den Prozess sendet. Außerdem nohupleitet die Standardausgabe und Standardfehler (aber nicht die Standardeingabe) in eine Datei, aber nur , wenn sie mit einem Anschluss verbunden, die wiederum, sie sind es nicht.

Abnehmen von einem 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$ 

Verwenden Sie nohupdiese Option, um das Skript von seinem steuernden Terminal zu trennen, sodass es kein SIGHUP erhält, wenn das Terminal verschwindet. nohupLeitet auch die Standardausgabe und den Standardfehler des Skripts in eine Datei um, die aufgerufen wird, nohup.outwenn sie mit dem Terminal verbunden sind. Sie müssen sich selbst um die Standardeingabe kümmern.

Ein entferntes Terminal behalten

Wenn Sie den Befehl weiterhin auf einem Remote-Terminal ausführen möchten, ihn jedoch nicht an die SSH-Sitzung angehängt haben, führen Sie ihn in einem Terminal-Multiplexer wie Screen oder Tmux aus .

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

Sie können später erneut eine Verbindung zu dem Terminal herstellen, auf dem das Skript ausgeführt wird, indem Sie screen -S backup -rdals root auf diesem Computer aufrufen .

Automatisierung eines Fernbefehls

Öffnen Sie direkte Remotestammanmeldungen aus Sicherheitsgründen nicht zu weit. Erstellen Sie ein spezielles Schlüsselpaar, und geben Sie einen erzwungenen Befehl ein /root/.ssh/authorized_keys. Der Inhalt der öffentlichen Schlüsseldatei ist AAAA…== [email protected]; Fügen Sie eine durch Kommas getrennte Liste von Optionen hinzu, einschließlich der Option command="…", dass der Schlüssel nur zum Ausführen dieses bestimmten Befehls verwendet werden kann. Stellen Sie sicher, dass sich die Optionen und der Schlüssel in einer Zeile befinden.

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 'SO - hör auf böse zu sein'
quelle
Ich habe den ersten Befehl ausprobiert, den Sie aufgelistet haben. Es gibt keinen Hintergrund für die Box, die den Befehl ausgeführt hat. Der Cursor sitzt einfach da und wartet auf die Fertigstellung ... Vielleicht ist es ein Fehler?
LVLAaron am
Möglicherweise müssen Sie stdin auf dem fernen System nach / dev / null umleiten. Das könnte der Grund sein, warum ssh nicht existiert.
KeithB
Ich würde die -fOption hinzufügen , ssh auf der lokalen Seite auf "Hintergrund" zu setzen (dh Verbindungen zu beenden, zu schließen). Dies funktioniert in Verbindung mit der &. nohupist in diesem Fall optional, Sie können jedoch setsidstattdessen die Option verwenden.
Alexios
@KeithB Das Umleiten von stdin ist Teil davon, aber ich muss auch stdout und stderr umleiten: nohup macht das hier nicht, weil sie keine Terminals sind, und in der Tat ist nohup hier nicht nützlich.
Gilles 'SO- hör auf böse zu sein'
1
@erikbwork Bitte beachten Sie, dass ich absolut keine Ahnung von diesen Dingen habe, aber nach der Diskussion und den Kommentaren: Gilles verwendet die Option -t in seinen Befehlen nicht, sodass weder auf dem Client noch auf dem Server ein Pseudoterminal eingerichtet wird Seite. Daher wird kein HUP gesendet.
Binarus
12

Das Standardrezept zum Ausführen eines Remote-Befehls über eine Remote-Anmeldung wie SSH lautet wie folgt:

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

Wenn commandein Shell - Skript, das sich in eine Datei Pflege der Protokollierung, dann könnte man ändern command.logzu /dev/null. Sobald Sie dies gestartet haben, melden Sie sich sofort ab.

Du brauchst alles in dieser Leitung.

nohup Weist die Shell an, den Prozess nicht zu stören, wenn die Anmeldesitzung getrennt wird.

</dev/null sagt, es soll niemals auf Eingaben warten

>command.log Weist es an, Nachrichten an diese benannte Protokolldatei zu senden

2>&1weist es an, alle stderr-Nachrichten an dieselbe Protokolldatei zu senden. In einigen Fällen ist es besser, zwei Dateien zu haben, die zweite zum Sammeln von Fehlermeldungen und die erste zum Sammeln von normalen Aktivitätsnachrichten. Das kann es einfacher machen, zu überprüfen, ob alles richtig funktioniert hat.

& Weist ihn an, diesen Prozess zu trennen und im Hintergrund als Dämonprozess auszuführen.

Michael Dillon
quelle
10

Dieser Thread war sehr hilfreich, aber meine Lösung musste ein bisschen anders sein.

Die Bildschirmlösung gefällt mir nicht, weil ein Bildschirmprozess ausgeführt wird, den ich nicht benötige. Die verwendeten Weiterleitungen und Nohups lauten wie folgt:

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

arbeiteten NICHT für mich, wenn sie mit dem Befehl ssh verwendet wurden.

Ich habe ein Wrapper-Skript auf dem Remote-Computer erstellt, auf dem das eigentliche Skript ausgeführt wird. Das Wrapper-Skript legt die Umleitung und das Nohup fest. Etwas wie das:

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

Dann starte ich auf meinem Client-Rechner (beachte keine Umleitung):

# ssh remotemachine "backupwrapper.sh"
#

Der Befehl ssh kehrt sofort zurück, die Verbindung wird beendet und das Skript läuft weiter.

rui
quelle
6

Wie Nils sagt , ist es ein Sicherheitsrisiko, dass sich root über ssh anmeldet. Und ich rate davon ab, wesentliche Arbeiten auf einer Maschine ohne Protokoll auszuführen. Wenn etwas schief geht, wünschen Sie sich einige Fehlermeldungen zur Fehlerbehebung. Es gibt andere Antworten, die Ihnen zeigen, wie das geht. Aber so empfehle ich, genau das zu erreichen, wonach Sie gefragt haben. Es ist alles in sh (1) eingebaut. GNU-Bildschirm ist nicht erforderlich (obwohl ich das für eine clevere Lösung halte). Fügen Sie diese Zeichenfolge an Ihren Befehl: >&- 2>&- <&- &. >&-bedeutet enge stdout. 2>&-bedeutet nah stderr. <&-bedeutet enge stdin. &bedeutet im Hintergrund laufen, z

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

Sie sollten den Remote-Befehl im Hintergrund ausführen remoteserver. Auf diese Weise wird der Befehl ssh im Hintergrund ausgeführt localpc.

Abgesehen davon ist es eine schlechte Idee, root-ssh zuzulassen.

So remoteserverrichten Sie ein: Eine sudoers-Zeile, die /root/backup.shvom Benutzer als root ausgeführt wird backup.

Sie könnten diesen Benutzer ohne "gutes" Passwort erstellen.

Fügen Sie den Befehl sudo /root/backup.sh &als Befehl ~backup/.ssh/authorized_keyszusammen mit dem öffentlichen Schlüssel von localpc(wer auch immer das Skript auslöst) ein.

Nils
quelle
-1
#screen -d -m -S BACKUP ssh root@remoteserver /root/backup.sh
Killinks
quelle
2
Das ist nicht sehr nützlich: Wenn die SSH-Verbindung unterbrochen wird, werden stdout und stderr des Skripts geschlossen, was zu Problemen führen kann. Der Bildschirm sollte auf dem Remote-Computer ausgeführt werden (wie in der Antwort von enzotib ).
Gilles 'SO- hör auf böse zu sein'