Esta é apenas uma teoria, mas o que eu suspeito que está acontecendo é que as conexões TCP para suas sessões ssh estão morrendo, mas o "servidor em nuvem" não está detectando isso. Então, quando você vai fazer uma conexão com localhost -p 23xx
, o processo ssh ainda está lá e escutando, mas quando ele tenta enviar dados de volta para o Pi ele trava até que o número máximo de retransmissões TCP seja encontrado e finalmente decida se a conexão é morto e sai (você diz que trava para sempre, mas eu estou apostando que se você esperasse o suficiente você teria uma conexão redefinida).
Agora, supondo que você tenha o Pi configurado para reconectar se o túnel ssh morrer, você pode pensar que isso deve resolver o problema. Existem alguns problemas em potencial com essa ideia. Primeiro, o Pi também pode não estar detectando a conexão morta. Então, até que ele tente enviar dados e atingir o limite de retransmissões TCP, ele não verá a conexão inativa e fará a reconexão. O segundo problema em potencial é que, mesmo se detectar a conexão inativa e tentar se reconectar, ela não conseguirá estabelecer o ouvinte no servidor em nuvem, porque o ssh anterior ainda está lá e mantendo a porta.
A solução aqui é configurar o ssh para que ele possa detectar as conexões inativas. Existem algumas maneiras de fazer isso, TCP KeepAlive e SSH KeepAlive. (ref: link )
TCP KeepAlive ( TCPKeepAlive
configuração em ssh config) usa a funcionalidade nativa keep-alive do TCP. Basicamente, o kernel envia um TCP ACK vazio a cada X segundos, e quando ele não obtém um ACK de volta da outra extremidade (ou obtém um reset) ele fecha a conexão que notifica o aplicativo (SSH).
O SSH KeepAlive (as configurações ServerAlive*
& ClientAlive*
) é semelhante, mas opera em uma camada superior. Aqui, o processo SSH envia dados reais através da conexão e procura por uma resposta. Isto deve detectar uma conexão inoperante tão bem quanto um TCP KeepAlive normal, entretanto é mais provável manter a conexão viva porque os saltos no meio podem reconhecer pacotes TCP KeepAlive e ignorá-los, e timeout a conexão inativa. Mas um KeepAlive do SSH não pode ser reconhecido, pois parece um tráfego real para qualquer salto no meio.
TL; DR:
No raspberry Pis, adicione as seguintes configurações à configuração do seu cliente ssh ( ~/.ssh/config
ou /etc/ssh/ssh_config
):
ServerAliveInterval 15
ServerAliveCountMax 1
( documentação )
No servidor, adicione as seguintes configurações à sua configuração do daemon ssh ( /etc/ssh/sshd_config
):
ClientAliveInterval 20
ClientAliveCountMax 1
( documentação )
Note que eu fiz o valor do intervalo um pouco mais alto. A razão para isso é apenas para que ambos os lados não enviem suas mensagens KeepAlive ao mesmo tempo e se cruzam no fio. Não há nenhum dano real nisso, apenas uma pequena ineficiência. Também não importa qual lado é maior, contanto que seja diferente.