Execute comandos remotos, desconectando-se completamente da conexão ssh

48

Eu tenho 2 computadores localpce remoteserver.

Eu preciso localpcexecutar alguns comandos remoteserver. Uma das coisas que ele precisa fazer é iniciar um script de backup que seja executado por várias horas. Eu gostaria que o comando localpc"disparasse" e depois continuasse sendo totalmente independente remoteserver, como localpcse nunca estivesse lá em primeiro lugar.

Isto é o que eu fiz até agora:

remoteserver contém possui o script:

/root/backup.sh

localpc está programado para executar isso:

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

Estou fazendo isso da maneira certa? Existe uma maneira melhor de fazer isso? Terei algum problema em fazê-lo desta maneira?

LVLAaron
fonte
stackoverflow.com/questions/19996089/... e stackoverflow.com/questions/29142/... fornecer um número de abordagens úteis para este problema não usando a tela / tmux etc ...
Paul

Respostas:

47

Você provavelmente deve usar screenno host remoto, para ter um comando desanexado real:

ssh root@remoteserver screen -d -m ./script
enzotib
fonte
Eu gosto desta ideia. Quando o script terminar, a tela ainda estará em execução ... e eu teria que reconectá-lo da próxima vez que quisesse, certo?
precisa saber é o seguinte
@AaronJAnderson: não, dado que o comando não é um shell, quando termina também a sessão de tela termina.
enzotib
52

Perto, mas não exatamente.

Independentemente de qualquer terminal

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

Você precisa fechar todos os descritores de arquivo conectados ao soquete ssh, porque a sessão ssh não será fechada enquanto algum processo remoto tiver o soquete aberto. Se você não estiver interessado na saída do script (presumivelmente porque o próprio script cuida da gravação em um arquivo de log), redirecione-o para /dev/null(mas observe que isso ocultará erros como não conseguir iniciar o script).

O uso nohupnão tem efeito útil aqui. nohuporganiza o programa que é executado para não receber um sinal HUP se o terminal de controle do programa desaparecer, mas aqui não há terminal em primeiro lugar, então nada enviará um SIGHUP para o processo do nada. Além disso, nohupredireciona a saída padrão e o erro padrão (mas não a entrada padrão) para um arquivo, mas apenas se eles estiverem conectados a um terminal, o que, novamente, não estão.

Desconectando de um 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$ 

Use nohuppara desanexar o script de seu terminal de controle para que ele não receba um SIGHUP quando o terminal desaparecer. nohuptambém redireciona a saída padrão do script e o erro padrão para um arquivo chamado nohup.outse estiver conectado ao terminal; você mesmo deve cuidar da entrada padrão.

Mantendo um terminal remoto

Se você deseja manter o comando em execução em um terminal remoto, mas não o anexa à sessão SSH, execute-o em um multiplexador de terminal, como Screen ou Tmux .

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

Posteriormente, você pode reconectar-se ao terminal em que o script está executando, invocando screen -S backup -rdcomo root nessa máquina.

Automatizando um Comando Remoto

Para uma segurança um pouco melhor, não abra logins remotos remotos diretos demais. Crie um par de chaves para fins especiais e dê a ele um comando forçado /root/.ssh/authorized_keys. O conteúdo do arquivo de chave pública é AAAA…== [email protected]; adicione uma lista de opções separadas por vírgula, incluindo as command="…"que especificam que a chave pode ser usada apenas para executar este comando específico. Certifique-se de manter as opções e a chave em uma linha.

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- parar de ser mau'
fonte
Eu tentei o primeiro comando que você listou. Ele não possui fundo na caixa que executou o comando. O cursor fica lá e aguarda a conclusão ... talvez seja um bug?
precisa saber é o seguinte
Pode ser necessário redirecionar o stdin para / dev / null no sistema remoto. Pode ser por isso que o ssh não está saindo.
KeithB
Eu adicionaria a -fopção de obter ssh para 'background' (ou seja, encerrar, fechar conexões) no lado local. Isso funcionará em conjunto com o &. nohupé opcional neste caso, mas você pode considerar o uso setsid.
Alexios
@KeithB Redirecionar stdin faz parte disso, mas também preciso redirecionar stdout e stderr: o nohup não fará isso aqui porque não são terminais, e na verdade o nohup não é útil aqui.
Gilles 'SO- stop be evil'
1
@erikbwork Observe que não tenho absolutamente nenhuma idéia sobre essas coisas, mas após a discussão e os comentários: Gilles não usa a opção -t em seus comandos; portanto, nenhum pseudo terminal será estabelecido, nem no cliente nem no servidor lado. Portanto, nenhum HUP será enviado.
Binarus 15/05/19
12

A receita padrão para executar um comando remoto a partir de um login remoto como SSH é a seguinte:

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

Se commandé um script de shell que cuida do log de um arquivo em si, você pode alterar command.logpara /dev/null. Depois de iniciar isso, faça logoff imediatamente.

Você precisa de tudo nessa linha.

nohup informa ao shell para não atrapalhar o processo se a sessão de login estiver desconectada.

</dev/null diz para nunca esperar pela entrada

>command.log diz para enviar qualquer mensagem para esse arquivo de log nomeado

2>&1diz para enviar quaisquer mensagens stderr para o mesmo arquivo de log. Em alguns casos, é melhor ter dois arquivos, o segundo para coletar mensagens de erro e o primeiro para coletar mensagens de atividade normal. Isso pode facilitar a verificação de que tudo funcionou corretamente.

& diz para desanexar esse processo e executá-lo em segundo plano como um processo daemon.

Michael Dillon
fonte
10

Esse tópico foi muito útil, mas minha solução tinha que ser um pouco diferente.

Eu não gosto da solução de tela porque deixa um processo de tela em execução do qual não preciso. Os redirecionamentos e nohups usados ​​assim:

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

NÃO estavam trabalhando para mim quando usados ​​com o comando ssh.

Criei um script de wrapper na máquina remota que executa o script real. O script do wrapper define o redirecionamento e o nohup. Algo assim:

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

Em seguida, na minha máquina cliente, eu corro (observe sem redirecionamento):

# ssh remotemachine "backupwrapper.sh"
#

O comando ssh retorna imediatamente, a conexão é encerrada e o script permanece em execução.

rui
fonte
6

Como Nils diz , é um risco de segurança permitir que o root efetue login via ssh. E eu aconselho a não executar nenhum trabalho substancial em uma máquina sem um log. Se algo der errado, você desejará ter algumas mensagens de solução de problemas. Existem outras respostas mostrando como fazer isso. Mas aqui está como eu recomendo realizar exatamente o que você pediu. Está tudo embutido no sh (1). Não há necessidade de tela GNU (embora eu ache que seja uma solução inteligente). Anexar esta cadeia para o seu comando: >&- 2>&- <&- &. >&-significa fechar stdout. 2>&-significa stderr próximo. <&-significa stdin próximo. &significa executar em segundo plano, por exemplo

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

Você deve colocar o comando remoto em segundo plano remoteserver. A maneira como você faz isso fará o segundo plano do comando ssh localpc.

Além disso, é uma má idéia permitir o root-ssh.

Então, configure remoteserver: Uma linha de sudoers que será executada /root/backup.shcomo root pelo usuário backup.

Você pode criar esse usuário sem uma senha "boa".

Coloque o comando sudo /root/backup.sh &como comando em ~backup/.ssh/authorized_keys- junto com a chave pública de localpc(quem quer que acione esse script).

Nils
fonte
-1
#screen -d -m -S BACKUP ssh root@remoteserver /root/backup.sh
Killinks
fonte
2
Isso não é muito útil: se a conexão SSH acabar, o stdout e o stderr do script serão fechados, o que pode causar problemas. A tela deve estar em execução na máquina remota (como na resposta do enzotib ).
Gilles 'SO- stop be evil' em