Ejecute comandos remotos, desconectándose completamente de la conexión ssh

48

Tengo 2 computadoras localpcy remoteserver.

Necesito localpcejecutar algunos comandos en remoteserver. Una de las cosas que debe hacer es iniciar un script de respaldo que se ejecute durante varias horas. Me gustaría que el comando localpc"disparara" y luego se ejecutara de forma totalmente independiente remoteserver, como si localpcnunca hubiera estado allí en primer lugar.

Esto es lo que he hecho hasta ahora:

remoteserver contiene tiene el script:

/root/backup.sh

localpc está programado para ejecutar esto:

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

¿Estoy haciendo esto de la manera correcta? ¿Hay una mejor manera de hacer esto? ¿Tendré problemas para hacerlo de esta manera?

LVLAaron
fuente
stackoverflow.com/questions/19996089/… y stackoverflow.com/questions/29142/… proporcionan una serie de enfoques útiles para este problema que no utiliza screen / tmux, etc ...
Paul

Respuestas:

47

Probablemente debería usar screenen el host remoto, para tener un comando real separado:

ssh root@remoteserver screen -d -m ./script
enzotib
fuente
Me gusta esta idea. Cuando finalice el script, la pantalla seguirá ejecutándose ... y tendría que volver a conectarme de alguna manera la próxima vez que quisiera ejecutarlo, ¿verdad?
LVLAaron
@AaronJAnderson: no, dado que el comando no es un shell, cuando termina también termina la sesión de pantalla.
enzotib 01 de
52

Cerca, pero no exactamente.

Independientemente de cualquier terminal

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

Debe cerrar todos los descriptores de archivo que están conectados al socket ssh, porque la sesión ssh no se cerrará mientras algún proceso remoto tenga el socket abierto. Si no está interesado en la salida del script (presumiblemente porque el script mismo se encarga de escribir en un archivo de registro), rediríjalo a /dev/null(pero tenga en cuenta que esto ocultará errores como no poder iniciar el script).

Usar nohupno tiene ningún efecto útil aquí. nohuphace que el programa que ejecuta no reciba una señal HUP si el terminal de control del programa desaparece, pero aquí no hay ningún terminal en primer lugar, por lo que nada enviará un SIGHUP al proceso de la nada. Además, nohupredirige la salida estándar y el error estándar (pero no la entrada estándar) a un archivo, pero solo si están conectados a un terminal, que, de nuevo, no lo están.

Separarse de una 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$ 

Utilícelo nohuppara separar el script de su terminal de control para que no reciba un SIGHUP cuando desaparezca el terminal. nohuptambién redirige la salida estándar del script y el error estándar a un archivo llamado nohup.outsi están conectados al terminal; tienes que ocuparte de la entrada estándar tú mismo.

Mantener una terminal remota

Si desea mantener el comando ejecutándose en un terminal remoto pero no tenerlo conectado a la sesión SSH, ejecútelo en un multiplexor de terminal como Screen o Tmux .

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

Más tarde, puede volver a conectarse al terminal donde se ejecuta el script invocando screen -S backup -rdcomo root en esa máquina.

Automatizar un comando remoto

Para una seguridad ligeramente mejor, no abra los inicios de sesión remotos remotos directos demasiado. Cree un par de teclas de propósito especial y dele un comando forzado /root/.ssh/authorized_keys. El contenido del archivo de clave pública es AAAA…== [email protected]; agregue una lista de opciones separadas por comas, incluida la command="…"que especifica que la clave solo se puede usar para ejecutar este comando específico. Asegúrese de mantener las opciones y la clave en una sola línea.

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- deja de ser malvado'
fuente
He intentado el primer comando que enumeraste. No tiene antecedentes en el cuadro que ejecutó el comando. El cursor simplemente se sienta allí y espera su finalización ... ¿tal vez es un error?
LVLAaron
Es posible que deba redirigir stdin a / dev / null en el sistema remoto. Esa puede ser la razón por la que ssh no está saliendo.
KeithB
Agregaría la -fopción de obtener ssh en 'fondo' (es decir, terminar, cerrar conexiones) en el lado local. Esto funcionará junto con el &. nohupes opcional en este caso, pero puede considerar usarlo en su setsidlugar.
Alexios
@KeithB Redireccionar stdin es parte de él, pero también necesito redirigir stdout y stderr: nohup no lo hará aquí porque no son terminales, y de hecho nohup no es útil aquí.
Gilles 'SO- deja de ser malvado'
1
@erikbwork Tenga en cuenta que no tengo absolutamente ninguna idea sobre esas cosas, pero después de la discusión y los comentarios: Gilles no utiliza la opción -t en sus comandos, por lo que no se establecerá ningún pseudo terminal, ni en el cliente ni en el servidor lado. Por lo tanto, no se enviará HUP.
Binarus
12

La receta estándar para ejecutar un comando remoto desde un inicio de sesión remoto como SSH es la siguiente:

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

Si se commandtrata de un script de shell que se encarga de iniciar sesión en un archivo, entonces puede cambiarlo command.loga /dev/null. Una vez que comience esto, cierre la sesión de inmediato.

Necesitas todo en esa línea.

nohup le dice al shell que no interrumpa el proceso si la sesión de inicio de sesión está desconectada.

</dev/null le dice que nunca espere entrada

>command.log le dice que envíe cualquier mensaje a este archivo de registro con nombre

2>&1le dice que envíe cualquier mensaje stderr al mismo archivo de registro. En algunos casos, es mejor tener dos archivos, el segundo para recopilar mensajes de error y el primero para recopilar mensajes de actividad normal. Eso puede facilitar la verificación de que todo funcionó correctamente.

& le dice que desconecte este proceso y lo ejecute en segundo plano como un proceso demonio.

Michael Dillon
fuente
10

Este hilo fue muy útil, pero mi solución tenía que ser un poco diferente.

No me gusta la solución de pantalla porque deja un proceso de pantalla en ejecución que no necesito. Las redirecciones y nohups se usan así:

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

NO funcionaban para mí cuando se usaba con el comando ssh.

Creé un script de envoltura en la máquina remota que ejecuta el script real. El script de contenedor establece la redirección y nohup. Algo como esto:

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

Luego, en mi máquina cliente, ejecuto (no hay redirección):

# ssh remotemachine "backupwrapper.sh"
#

El comando ssh regresa inmediatamente, la conexión finaliza y el script se deja en ejecución.

rui
fuente
6

Como dice Nils , es un riesgo de seguridad permitir que root inicie sesión a través de ssh. Y desaconsejo ejecutar cualquier trabajo sustancial en una máquina sin un registro. Si algo sale mal, desearía tener algunos mensajes de solución de problemas. Hay otras respuestas que le muestran cómo hacerlo. Pero así es como recomiendo lograr lo que pediste. Todo está integrado en sh (1). No hay necesidad de pantalla GNU (aunque creo que es una solución inteligente). Anexar esta cadena para su comando: >&- 2>&- <&- &. >&-significa estrecho stdout. 2>&-significa stderr cercano. <&-significa estrecho stdin. &significa correr en segundo plano, por ejemplo

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

Debe poner en segundo plano el comando remoto remoteserver. La forma en que lo haga pondrá en segundo plano el comando ssh localpc.

Aparte de eso, es una mala idea permitir root-ssh.

Así que configúrelo en remoteserver: una línea de sudoers que se ejecutará /root/backup.shcomo root por usuario backup.

Puede crear ese usuario sin contraseña "buena".

Coloque el comando sudo /root/backup.sh &como comando en ~backup/.ssh/authorized_keys- junto con la clave pública de localpc(quien desencadena ese script).

Nils
fuente
-1
#screen -d -m -S BACKUP ssh root@remoteserver /root/backup.sh
Killinks
fuente
2
Eso no es muy útil: si la conexión SSH se corta, se cerrarán stdout y stderr del script, lo que puede causar problemas. La pantalla debería estar ejecutándose en la máquina remota (como en la respuesta de enzotib ).
Gilles 'SO- deja de ser malvado'