2009-09-08 13:04:22 +0000 2009-09-08 13:04:22 +0000
244
244

Como manter um túnel SSH aberto de forma fiável?

Utilizo um túnel SSH do trabalho para contornar várias firewalls idoticas (o meu patrão não tem problema :)). O problema é que, passado algum tempo, a ligação ssh geralmente fica suspensa, e o túnel está partido.

Se eu pudesse pelo menos monitorizar o túnel automaticamente, poderia reiniciar o túnel quando este estiver pendurado, mas ainda nem sequer descobri uma maneira de o fazer.

Pontos de bónus para aquele que me possa dizer como evitar que a minha ligação ssh fique pendurada, claro!

Respostas (16)

296
296
296
2009-09-08 13:43:51 +0000

Parece que precisa de autossh . Isto irá monitorizar um túnel ssh e reiniciá-lo conforme necessário. Usamo-lo há alguns anos e parece funcionar bem.

autossh -M 20000 -f -N your_public_server -R 1234:localhost:22 -C

Mais detalhes sobre o parâmetro -M aqui

40
40
40
2009-09-28 13:47:26 +0000

Todas as firewalls de estado esquecem uma ligação após não terem visto um pacote para essa ligação durante algum tempo (para evitar que as tabelas de estado fiquem cheias de ligações onde ambas as extremidades morreram sem fechar a ligação). A maioria das implementações TCP enviarão um pacote keepalive após um longo período sem ouvir do outro lado (2 horas é um valor comum). Se, no entanto, houver uma firewall de estado que esqueça a ligação antes que os pacotes keepalive possam ser enviados, uma ligação de longa duração mas inactiva morrerá.

Se for esse o caso, a solução é evitar que a ligação se torne ociosa. O OpenSSH tem uma opção chamada ServerAliveInterval que pode ser usada para evitar que a ligação fique ociosa durante demasiado tempo (como bónus, detectará quando o par morreu mais cedo, mesmo que a ligação esteja ociosa).

24
24
24
2010-05-29 13:45:08 +0000

Na sua própria máquina mac ou linux configure o seu ssh manter o ssh servidor vivo a cada 3 minutos. Abra um terminal e coloque o seu .ssh invisível em sua casa:

cd ~/.ssh/

depois crie um ficheiro de configuração com 1 linha:

echo "ServerAliveInterval 180" >> config

deve também adicionar:

ServerAliveCountMax xxxx (high number)

o padrão é 3 pelo que o ServerAliveInterval 180 deixará de enviar após 9 minutos (3 do intervalo de 3 minutos especificado pelo ServerAliveInterval).

23
23
23
2009-09-22 14:58:15 +0000

Utilizei o seguinte guião Bash para continuar a desovar novos túneis ssh quando o anterior morre. Utilizar um script é útil quando não se quer ou não se pode instalar pacotes adicionais ou utilizar o compilador.

while true
do
  ssh <ssh_options> [user@]hostname
  sleep 15
done

Note que isto requer um ficheiro-chave para estabelecer a ligação automaticamente, mas é o caso do autossh, também.

21
21
21
2016-07-28 06:10:14 +0000

Systemd é idealmente adequado para isto.

Criar um ficheiro de serviço /etc/systemd/system/sshtunnel.service contendo:

[Unit]
Description=SSH Tunnel
After=network.target

[Service]
Restart=always
RestartSec=20
User=sshtunnel
ExecStart=/bin/ssh -NT -o ServerAliveInterval=60 -L 5900:localhost:5900 user@otherserver

[Install]
WantedBy=multi-user.target

(Modificar o comando ssh para se adequar)

  • isto será executado como utilizador sshtunnel por isso certifique-se de que o utilizador existe primeiro
  • emissão systemctl enable sshtunnel para o configurar para começar no momento do arranque
  • emissão systemctl start sshtunnel para começar imediatamente

Actualização Jan 2018 : algumas distros (e. g. Fedora 27) podem utilizar a política SELinux para impedir a utilização de SSH do init systemd, caso em que será necessário criar uma política personalizada para proporcionar as isenções necessárias.

11
11
11
2013-11-28 01:04:34 +0000

Parece-me que estão todos a interpretar mal o ServerAliveCountMax. Como entendo os documentos, é o número de mensagens vivas do servidor que podem ficar sem resposta sem que a ligação seja terminada. Portanto, em casos como o que estamos a discutir aqui, defini-lo a um valor elevado apenas garantirá que uma ligação suspensa não será detectada e terminada!

A simples definição do ServerAliveInterval deverá ser suficiente para resolver o problema com uma firewall esquecendo a ligação, e deixar o ServerAliveCountMax em baixo permitirá que o fim de origem note a falha e termine se a ligação falhar de qualquer forma.

O que se pretende é, 1) que a ligação fique permanentemente aberta em circunstâncias normais, 2) que a falha de ligação seja detectada e que o lado de origem saia em caso de falha, e 3) que o comando ssh seja reemitiado cada vez que sai (como o faz depende muito da plataforma, o script “while true” sugerido por Jawa é uma das formas, no OS X eu configurei de facto um item de lançamento).

9
9
9
2014-03-08 21:30:40 +0000

Utilizar sempre a opção ServerAliveInterval SSH caso os problemas do túnel sejam gerados por sessões NAT expiradas.

Use sempre um método de respawning no caso de a conectividade descer por completo, tem pelo menos três opções aqui:

  • programa autossh
  • bash script (while true do ssh ...; sleep 5; done) não remover o comando sleep, ssh pode falhar rapidamente e irá repintar demasiados processos

- /etc/inittab, para ter acesso a uma caixa enviada e instalada noutro país, por trás do NAT, sem reencaminhar a porta para a caixa, pode configurá-la para criar um túnel ssh de volta para si:

  • upstart script no Ubuntu, onde /etc/inittab não está disponível:

ou utilizar sempre os dois métodos.

6
6
6
2013-05-30 13:32:05 +0000

Resolvi este problema com isto:

Editar

~/.ssh/config

E acrescentar

ServerAliveInterval 15
ServerAliveCountMax 4

De acordo com man page para ssh_config:

ServerAliveCountMax
         Sets the number of server alive messages (see below) which may be
         sent without ssh(1) receiving any messages back from the server.
         If this threshold is reached while server alive messages are
         being sent, ssh will disconnect from the server, terminating the
         session. It is important to note that the use of server alive
         messages is very different from TCPKeepAlive (below). The server
         alive messages are sent through the encrypted channel and there‐
         fore will not be spoofable. The TCP keepalive option enabled by
         TCPKeepAlive is spoofable. The server alive mechanism is valu‐
         able when the client or server depend on knowing when a connec‐
         tion has become inactive.

         The default value is 3. If, for example, ServerAliveInterval
         (see below) is set to 15 and ServerAliveCountMax is left at the
         default, if the server becomes unresponsive, ssh will disconnect
         after approximately 45 seconds. This option applies to protocol
         version 2 only.

 ServerAliveInterval
         Sets a timeout interval in seconds after which if no data has
         been received from the server, ssh(1) will send a message through
         the encrypted channel to request a response from the server. The
         default is 0, indicating that these messages will not be sent to
         the server. This option applies to protocol version 2 only.
4
4
4
2015-06-06 23:41:10 +0000

ExitOnForwardFailure yes é um bom coadjuvante das outras sugestões. Se liga mas não consegue estabelecer o encaminhamento do porto, é tão inútil para si como se não tivesse ligado de todo.

1
1
1
2012-03-13 12:11:18 +0000

Um pouco de hack, mas eu gosto de usar o ecrã para manter isto. Actualmente, tenho um comando à distância que está a funcionar há semanas.

Exemplo, começando localmente:

screen
ssh -R ......

Quando o avanço remoto é aplicado, e tem uma concha no computador remoto:

screen
Ctrl + a + d

Tem agora um avanço remoto ininterrupto. O truque é executar o ecrã em ambas as extremidades

1
1
1
2015-07-30 14:02:55 +0000

Eu próprio tive recentemente este problema, porque estas soluções exigem que volte a introduzir a palavra-passe sempre que utilizar uma palavra-passe de início de sessão que utilizei sshpass num laço juntamente com uma mensagem de texto para evitar ter a palavra-passe no ficheiro de lote.

Pensei em partilhar a minha solução sobre este assunto no caso de mais alguém ter o mesmo problema:

#!/bin/bash
read -s -p "Password: " pass
while true
do
    sshpass -p "$pass" ssh user@address -p port
    sleep 1
done
1
1
1
2009-09-08 14:09:33 +0000

enquanto existem ferramentas como o autossh que ajuda a reiniciar a sessão ssh… o que eu acho realmente útil é executar o comando ‘screen’. Permite-lhe RESUMEAR as suas sessões ssh mesmo depois de se desligar. Especialmente útil se a sua ligação não for tão fiável como deveria ser.

…não se esqueça de marcar esta é a resposta ‘correcta’ se isso o ajudar k! ;-)

1
1
1
2009-09-08 13:17:28 +0000

Tive a necessidade de manter um túnel SSH a longo prazo. A minha solução era correr a partir de um servidor Linux, e é apenas um pequeno programa em C que faz respawns ssh usando autenticação baseada em chaves.

Não tenho a certeza sobre o enforcamento, mas tive túneis que morreram devido a timeouts.

Eu adoraria fornecer o código para o respawner, mas parece que não consigo encontrá-lo agora.

0
0
0
2017-07-15 00:04:11 +0000

Como autossh não satisfaz as nossas necessidades (existe com erro se não conseguir ligar-se ao servidor logo na primeira tentativa), escrevemos uma aplicação de bash pura: https://github.com/aktos-io/link-with-server

Cria um túnel invertido para a porta sshd da NODE (22) no servidor por defeito. Se precisar de executar quaisquer outras acções (como reencaminhar portas adicionais, enviar emails em ligação, etc…) pode colocar os seus scripts on-connect e pastas on-disconnect.

0
0
0
2009-09-28 10:27:21 +0000

Já tive problemas semelhantes com o meu anterior ISP. Para mim foi o mesmo com qualquer ligação tcp, visitando websites ou enviando correio.

A solução era configurar uma ligação VPN sobre UDP(eu estava a utilizar OpenVPN). Esta ligação era mais tolerante ao que quer que fosse que causasse as desconexões. Depois é possível executar qualquer serviço através desta ligação.

Ainda pode haver problemas com a ligação, mas como o túnel será mais tolerante, qualquer sessão ssh sentirá um pequeno atraso em vez de ser desconectada.

Para o fazer, necessitará de um serviço VPN online que poderá configurar no seu próprio servidor.

0
0
0
2020-02-20 15:09:46 +0000

Poderia muito simplesmente usar o comando tmux no seu servidor remoto. Permite-lhe abrir uma “sessão” na máquina remota onde o seu código remoto será executado.

Então pode sair (ou perder a ligação no seu caso) da máquina remota sem se preocupar, dado que o seu código está a correr em segurança na sua sessão tmux.

Finalmente, quando voltar a ligar no servidor remoto, só precisa de tmux attach para voltar à sessão que tinha anteriormente aberta e pronto.