Questão Como manter de forma confiável um túnel SSH aberto?


Eu uso um túnel SSH do trabalho para ir em torno de vários firewalls idóticos (está tudo bem com o meu chefe :)). O problema é que, depois de um tempo, a conexão ssh geralmente trava e o túnel está quebrado.

Se eu pudesse pelo menos monitorar o túnel automaticamente, eu poderia reiniciar o túnel quando ele trava, mas eu nem imaginei uma maneira de fazer isso.

Pontos de bônus para quem pode me dizer como evitar que minha conexão ssh seja suspensa, é claro!


200


origem


É o seu túnel morto por inatividade? Eu tive esse problema ao tunelar portas do meu telefone, então eu finalmente terminei de gerar comandos fictícios na conexão para torná-lo "vivo" usando o watch comando como: watch -n1 60 echo "wiiiii". O túnel não morrerá a menos que a rede esteja quebrada ou você não a use. - erm3nda
Relacionado: unix.stackexchange.com/q/200239 - sampablokuper


Respostas:


Parece que você precisa autossh. Isto irá monitorar um túnel ssh e reiniciá-lo conforme necessário. Nós usamos isso 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


239



+1 para autossh, faz o que diz na lata. Acredito que parte de sua funcionalidade também seja enviar pacotes de estilo keep-alive para evitar qualquer tipo de tempo limite. - akent
Você poderia colocar o exemplo de túnel usando autossh na resposta? - Ehtesh Choudhury
autossh -f -nNT -i ~/keypair.pem -R 2000:localhost:22 username@myoutsidebox.com   Você pode notar que eu configurei isso usando -nNT que não cria um terminal remoto para que eu possa colocar o autossh no plano de fundo, e a opção -i para que o SSH use um arquivo .pem. Se você estiver mantendo uma conexão aberta o tempo todo, eu definitivamente recomendo passar pela configuração extra. - juckele
Por que vale a pena, parece que normalmente é melhor omitir o -M parâmetro: bugs.debian.org/cgi-bin/bugreport.cgi?bug=351162 - rinogo
Se não estiver funcionando e você estiver usando chaves, verifique esta resposta - serverfault.com/a/545093/288788 - muttonUp


Todos os firewalls com informações de estado esquecem-se de uma conexão depois de não ver um pacote dessa conexão por algum tempo (para impedir que as tabelas de estado fiquem cheias de conexões em que ambas as extremidades morrem sem fechar a conexão). A maioria das implementações TCP enviará um pacote keepalive após um longo período de tempo sem ouvir do outro lado (2 horas é um valor comum). Se, no entanto, houver um firewall com estado que se esquece da conexão antes que os pacotes keepalive possam ser enviados, uma conexão de longa duração, mas ociosa, será interrompida.

Se for esse o caso, a solução é evitar que a conexão fique ociosa. O OpenSSH tem uma opção chamada ServerAliveInterval que pode ser usado para evitar que a conexão fique ociosa por muito tempo (como bônus, ela detectará quando o peer morreu mais cedo, mesmo se a conexão estiver inativa).


34



O intervalo especificado está em segundos, para que você possa fornecer alguns ajustes finos. Se o firewall com monitoração de estado tiver um tempo limite ocioso de 5 minutos, 60 ou 120 segundos serão suficientes para manter a conexão aberta. É uma das maneiras de manter minhas sessões ssh no meu roteador doméstico abertas. - Darren Hall
Obrigado, isso ajudou. Mas note (a partir de uma resposta abaixo do ranking aqui, superuser.com/a/146641/115515) que, se você especificar ServerAliveInterval e não ServerAliveCountMax, talvez o ssh seja desconectado intencionalmente mais cedo do que o desejado. - metamatt
@metamatt, essa resposta de baixa classificação que você faz referência é menor classificada por um bom motivo: É ERRADO. - Lambart


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

cd ~/.ssh/ 

em seguida, crie um arquivo de configuração de 1 linha com:

echo "ServerAliveInterval 180" >> config

você também deve adicionar:

ServerAliveCountMax xxxx (high number)

o padrão é 3, portanto, o ServerAliveInterval 180 irá parar de enviar após 9 minutos (3 do intervalo de 3 minutos especificado por ServerAliveInterval).


22



Observe que seu comando não é recomendado se você já tiver um arquivo de configuração. Usando >> para redirecionamento seria muito melhor! - Peltier
porque ServerAliveInterval 180 nos dê 6 minutos? intuição me faz tentar isso: 180/60 == 3. Então, faz ServerAliveInterval trabalhar em múltiplos de 30 segundos? - nemesisfixx
@mcnemesis: ServerAliveInterval 180 significa 3 minutos. ServerAliveCountMax padrão de 3 significa 3 desses intervalos, portanto, 9 minutos. - metamatt
Eu estou votando esta resposta porque obrigado por mencionar ServerAliveCountMax, e o que acontece se você especificar ServerAliveInterval sem ServerAliveCountMax. Mas, como os comentários anteriores, percebo que o cálculo "will stop sending after" está errado, e acho que essa resposta serviria melhor se apenas desse as informações sobre essas opções, não nos dizendo como aplicá-las com os comandos cd e echo . - metamatt
Downvoting porque não faz sentido definir ServerAliveCountMax como um "número alto". ServerAliveCountMax especifica quantas vezes ele tentará enviar a mensagem "keepalive" antes de desistir. O padrão é 3, então com o ServerAliveInterval 180, ele irá parar de enviar APENAS se o servidor NÃO RESPONDE depois de 9 minutos, caso em que sua conexão provavelmente está realmente morta. - Lambart


Eu usei o seguinte script Bash para continuar gerando novos túneis ssh quando o anterior morre. Usar um script é útil quando você não quer ou não pode instalar pacotes adicionais ou usar o compilador.

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

Observe que isso requer um arquivo de chaves para estabelecer a conexão automaticamente, mas esse também é o caso do autossh.


20



Você deve adicionar algum motivo para usar esse script no autossh, ou é apenas mais fácil assim? - kyrias
Isso não ajudaria se o próprio ssh congela, não é? - nafg
Ajuda se você não puder instalar coisas no servidor. O autossh não vem pré-instalado e a bureucracy às vezes é muito obtuso. - quarkex
Sim, preferível não ter que instalar coisas. Eu venho fazendo isso por um ano como minha única maneira de manter uma máquina remota acessível (até mesmo configurar o crontab para executá-lo na reinicialização). Nunca falhou e, mais importante, sei por que nunca irá falhar. - sudo


Com certeza me parece que você está interpretando mal o ServerAliveCountMax. Pelo que entendi os documentos, é o número de mensagens vivas do servidor que podem ficar sem resposta sem que a conexão seja terminada. Portanto, em casos como os que estamos discutindo aqui, configurá-lo com um valor alto apenas garantirá que uma conexão interrompida não seja detectada e terminada!

Simplesmente definir ServerAliveInterval deve ser suficiente para resolver o problema com um firewall esquecendo a conexão, e deixar ServerAliveCountMax baixo permitirá que a extremidade de origem perceba a falha e termine se a conexão falhar de qualquer maneira.

O que você quer é, 1) que a conexão permaneça aberta permanentemente em circunstâncias normais, 2) que a falha de conexão seja detectada e que o lado de origem saia com falha, e 3) que o comando ssh seja reeditado toda vez exits (como você faz isso é muito dependente da plataforma, o script "while true" sugerido por Jawa é unidirecional, no OS XI realmente configurar um item launchd).


9





Sempre use ServerAliveInterval Opção SSH, caso os problemas de túnel sejam gerados por sessões NAT expiradas.

Sempre use um método de respawn caso a conectividade seja completamente reduzida, você tem pelo menos três opções aqui:

  • programa autossh
  • script bash (while true do ssh ...; sleep 5; done) não remova o comando sleep, ssh pode falhar rapidamente e você vai reaparecer muitos processos
  • /etc/inittab, para ter acesso a uma caixa enviada e instalada em outro país, por trás do NAT, sem o encaminhamento de porta para a caixa, você pode configurá-lo para criar um túnel ssh de volta para você:

    tun1:2345:respawn:/usr/bin/ssh -i /path/to/rsaKey -f -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip 'sleep 365d'
    
  • script upstart no Ubuntu, onde /etc/inittab não está disponível:

    start on net-device-up IFACE=eth0
    stop on runlevel [01S6]
    respawn
    respawn limit 180 900
    exec ssh -i /path/to/rsaKey -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip
    post-stop script
        sleep 5
    end script
    

ou sempre use os dois métodos.


9



+1 para opção inline, caso você não o queira para todas as suas conexões SSH - user1146334
Você escreve "no caso de a conectividade cair completamente". Agora eu não entendo, que problemas o autossh conserta, e o que não faz? Eu pensei, claro, que iria cuidar de qualquer conexão quebrada, como desconectar o cabo por algumas horas, mas talvez não? - Mads Skjern


O Systemd é ideal para isso.

Crie um arquivo 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

(Modifique o comando ssh para se adequar)

  • isso será executado como usuário sshtunnel Portanto, verifique se o usuário existe primeiro
  • questão systemctl enable sshtunnel para configurá-lo para iniciar no momento da inicialização
  • questão systemctl start sshtunnel para começar imediatamente

Atualizar janeiro de 2018: algumas distros (por exemplo, Fedora 27) podem usar a política do SELinux para impedir o uso do SSH a partir do init do systemd, caso em que uma política personalizada precisará ser criada para fornecer as isenções necessárias.


8



Isso parece muito semelhante à minha essência: gist.github.com/guettli/… O feedback é bem-vindo! - guettli
Excelente para um systemd sistema. Se alguém usa Restart=on-failure em seguida, matar manualmente o cliente SSH não resultará em um restart-by-systemd, pois o cliente SSH sairá com sucesso. - David Tonhofer
Se você quiser iniciar o ssh a partir de um script (bash) fornecido como argumento para ExecStart por exemplo, para construir o ssh lista de argumentos, fazer verificações básicas etc, em seguida, chamá-lo a partir do script como assim exec /bin/ssh -N .... Aqui está o meu comando: exec /bin/ssh -N -oExitOnForwardFailure=Yes -oTCPKeepAlive=no -oServerAliveInterval=5 -oServerAliveCountMax=6 -i "${LOCAL_PRIVATE_KEY}" -L "${TUNNEL_INLET}:${TUNNEL_OUTLET}" "${REMOTE_USER}@${REMOTE_MACHINE}" Onde TUNNEL_INLET="127.0.0.1:3307" e TUNNEL_OUTLET="127.0.0.1:3306" - David Tonhofer


Eu resolvi esse problema com isso:

Editar

~/.ssh/config

E adicione

ServerAliveInterval 15
ServerAliveCountMax 4

De acordo com página man 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.

6



A cada 15 segundos parece com muita freqüência para pingar o servidor. - Lambart
@Lambart, mas se a conexão é realmente escamosa e elimina as conexões com frequência, ela pelo menos detecta uma conexão inativa e dá a oportunidade de tentar mais cedo. - binki


ExitOnForwardFailure yes é um bom complemento para as outras sugestões. Se ele se conecta, mas não pode estabelecer o encaminhamento de porta, é tão inútil para você como se não tivesse sido conectado.


3



Esta é uma ideia muito boa. Mesmo o autossh é inútil se a conexão anterior for percebida como expirada anteriormente no lado remoto do que no host local, pois nesse caso o host local tentará se conectar novamente, mas o encaminhamento não poderá ser estabelecido porque a porta ainda está aberta. - Raúl Salinas-Monteagudo