Corrigindo desconexoes SSH: Keepalive e Timeouts
Por que o SSH desconecta sozinho?
Conclusao: Na maioria das vezes, um NAT/firewall no caminho ou o sshd silenciosamente mata uma conexao ociosa (sem trafego). Se morre com
Broken pipeapos uma breve pausa, o keepalive -- pequenos pacotes periodicos -- nao esta ativo. ConfigurarServerAliveIntervalno cliente ouClientAliveIntervalno servidor resolve a maioria dos casos.
Se o SSH "funciona enquanto estou digitando mas morre quando me afasto", timeout ocioso e quase sempre o culpado. Uma conexao TCP sobrevive ao silencio por um tempo, mas dispositivos NAT, firewalls stateful e balanceadores de carga no caminho removem sessoes que ficam quietas por muito tempo. Apos a remocao, sua proxima tecla nao tem para onde ir, e a sessao morre com mensagens como estas:
client_loop: send disconnect: Broken pipe
Write failed: Broken pipe packet_write_wait: Connection to 192.0.2.10 port 22: Broken pipe
Timeout, server not responding.
Por outro lado, se cai enquanto voce esta trabalhando ativamente, ou no mesmo tempo decorrido exato a cada sessao, suspeite de um limite de sessao explicito no servidor ou de um link instavel (coberto abaixo). O primeiro passo mais rapido e determinar se morre ocioso ou morre em uso.
Pre-requisitos
- Cliente e servidor ambos Ubuntu / Linux tipico (OpenSSH)
- Edite
~/.ssh/configno cliente;/etc/ssh/sshd_configno servidor - Aplicar mudancas no servidor precisa de
sudoe um reload do sshd
Queda ociosa ou queda em uso -- como distinguir?
Conclusao: Se morre enquanto fica ocioso, e um timeout ocioso (NAT / firewall /
ClientAliveInterval). Se morre mesmo enquanto voce mantem a tela atualizando (ex.: executandotop), suspeite de qualidade do link ou um limite de sessao explicito. O primeiro e corrigido com keepalive; o segundo precisa de uma abordagem diferente.
Para dividir a causa em duas, primeiro teste se trafego constante mantem a conexao viva.
# Mantem a conexao ocupada com saida periodica leve $ ssh user@server 'while true; do date; sleep 30; done'
- Para de cair -> o silencio era a causa: um timeout ocioso. Keepalive resolve (proxima secao).
- Continua caindo -> suspeite de link instavel (Wi-Fi / movel) ou timeout fixo no servidor (outras configuracoes do
sshd_config, PAM, ou limite rigido de balanceador de carga).
Manter a conexao com ssh -v e ler o log no momento da queda torna isso conclusivo.
$ ssh -v user@server
debug1: client_loop: send disconnect: Broken pipe
Se o trafego de keepalive parou logo antes do corte, ou server not responding apareceu, indica qual lado desistiu primeiro.
Se o tempo-ate-cair e quase constante toda vez, um timeout artificial e provavel (conntrack do NAT, ou ClientAliveInterval x ClientAliveCountMax do servidor). Se varia, incline-se para um problema de qualidade do link.
Lado do cliente: como configurar ServerAlive?
Conclusao: Coloque
ServerAliveInterval 60no~/.ssh/configdo cliente primeiro. Mesmo sem trafego, o ssh envia uma requisicao pelo canal criptografado a cada 60 segundos, mantendo a sessao NAT viva e detectando um servidor morto. Funciona apenas do cliente, mesmo quando voce nao pode mexer no servidor (hosts compartilhados, etc.).
ServerAliveInterval e o numero de segundos de silencio do servidor apos o qual o ssh envia uma requisicao pelo canal criptografado. O padrao e 0 (desabilitado). ServerAliveCountMax (padrao 3) e quantos probes podem ficar sem resposta antes do ssh desconectar.
# ~/.ssh/config
Host *
ServerAliveInterval 60
ServerAliveCountMax 3Com isso, um pequeno pacote flui a cada 60 segundos para que a sessao NAT/firewall permaneca viva, prevenindo quedas ociosas. Ao mesmo tempo, se o servidor realmente morrer, o ssh desiste apos 60s x 3 = ~180s em vez de deixar uma sessao zumbi.
Para testar ad hoc, use -o.
$ ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 user@server
Host * aplica a todas as conexoes; limite a um bloco Host myserver para restringir. Mantenha ~/.ssh/config no modo 600 -- permissoes muito frouxas podem fazer com que seja ignorado.
Definir ServerAliveInterval muito baixo significa que uma breve instabilidade esgota o ServerAliveCountMax e torna quedas mais provaveis. Em links instaveis, nao reduza o intervalo agressivamente; aumente o count (ex.: Interval 30 / CountMax 6 da ~180s de margem).
Lado do servidor: como configurar ClientAlive?
Conclusao: Se voce gerencia o servidor, coloque
ClientAliveInterval 60em/etc/ssh/sshd_config. O sshd envia uma requisicao pelo canal criptografado para cada cliente, entao voce previne quedas ociosas sem configurar cada cliente. Os mesmos parametros tambem permitem desconectar deliberadamente clientes ociosos -- a direcao depende do CountMax que voce combinar.
ClientAliveInterval e o espelho do ServerAliveInterval do cliente: o sshd envia um probe apos N segundos de silencio do cliente. Padrao 0 (desabilitado). ClientAliveCountMax tem padrao 3.
# /etc/ssh/sshd_config ClientAliveInterval 60 ClientAliveCountMax 3
Valide a sintaxe antes de aplicar. Quebrar a configuracao do sshd aqui pode te trancar para fora, entao sempre faca isso com uma segunda sessao aberta.
# Verificacao de sintaxe (captura erros antes de entrarem em vigor) $ sudo sshd -t # Recarregar a configuracao (sessoes existentes sao preservadas) $ sudo systemctl reload ssh
# sshd -t nao imprime nada quando a configuracao e valida
Note que o significado muda com a intencao:
- Manter conexoes vivas:
ClientAliveInterval 60sozinho mantem o keepalive fluindo e supera a remocao do NAT. UmCountMaxmaior e aceitavel. - Desconectar clientes ociosos (ex.: requisito de seguranca):
ClientAliveInterval 300/ClientAliveCountMax 1derruba um cliente silencioso apos cerca de 5 minutos (note queClientAliveCountMax 0em vez disso desabilita a terminacao).
Um restart pode derrubar conexoes existentes; prefira reload para aplicar mudancas. Execute sshd -t -> reload com uma segunda sessao SSH ainda aberta para se proteger contra bloqueio. Se o ufw bloquear ate o SSH, veja Troubleshooting ufw e SSH.
Como ServerAlive difere do TCPKeepAlive?
Conclusao:
ServerAliveInterval/ClientAliveIntervaloperam sobre o canal criptografado SSH -- nao podem ser falsificados e permitem ajustar o intervalo em segundos.TCPKeepAlivee keepalive na camada TCP, vinculado ao padrao do SO (tipicamente 2 horas de inicio ocioso) e falsificavel. Para prevencao de queda ociosa, use a familia ServerAlive da camada SSH.
As tres configuracoes comumente confundidas, por camada:
| Configuracao | Camada | Direcao | Notas |
|---|---|---|---|
ServerAliveInterval |
SSH (criptografado) | cliente->servidor | Definido no cliente. Nao falsificavel |
ClientAliveInterval |
SSH (criptografado) | servidor->cliente | Definido no servidor. Nao falsificavel |
TCPKeepAlive |
TCP | ambas direcoes | Padrao yes. Intervalo depende do SO |
Mesmo com TCPKeepAlive yes (o padrao do OpenSSH), a vivacidade e verificada, mas o tempo ocioso antes do keepalive TCP iniciar segue a configuracao do SO (no Linux, net.ipv4.tcp_keepalive_time, padrao 7200 segundos = 2 horas). Isso e lento demais para um NAT que corta em minutos. Para superar um timeout ocioso curto, o ServerAliveInterval com granularidade de segundos e a ferramenta certa.
# Para referencia: o inicio ocioso do keepalive TCP (segundos) $ sysctl net.ipv4.tcp_keepalive_time
net.ipv4.tcp_keepalive_time = 7200
Os manuais oficiais (man ssh_config / man sshd_config) afirmam que mensagens ServerAlive sao "enviadas pelo canal criptografado e portanto nao falsificaveis", enquanto TCPKeepAlive e falsificavel. O keepalive da camada SSH vence tanto em seguranca quanto em controle.
E se ainda cair apos configurar o keepalive?
Conclusao: Se o keepalive esta configurado e ainda cai, e um destes: (1) um timeout ocioso de NAT / LB menor que seu intervalo de keepalive, (2) o link em si oscilando, ou (3) outro timeout do servidor (PAM, limite rigido de balanceador de carga). A correcao e tornar o intervalo de keepalive confiavelmente menor que esse valor de ociosidade.
Percorra os suspeitos habituais quando o keepalive nao e suficiente.
# Procurar pistas de keepalive / disconnect / timeout no log detalhado $ ssh -v user@server 2>&1 | grep -iE 'alive|disconnect|timeout'
- NAT / firewall ocioso e curto: roteadores domesticos e LBs de nuvem podem expirar em aproximadamente 60-350 segundos. Defina
ServerAliveIntervalclaramente abaixo disso (se o LB e 60s, use30). - Link oscilando: links Wi-Fi / moveis caem fisicamente. Keepalive nao salva esses -- use tmux / mosh (abaixo) para tolerar desconexoes.
- Outro limite do servidor: um limite de sessao de balanceador de carga ou bastion, ou uma regra PAM, pode cortar em um tempo fixo. Verifique o motivo no servidor com
journalctl -u ssh.
# Verificar o motivo da desconexao no lado do servidor $ sudo journalctl -u ssh -n 100 --no-pager
Atras de um balanceador de carga na nuvem (AWS NLB / GCP, etc.), o timeout ocioso do proprio LB domina (AWS NLB tem padrao de 350 segundos). Sempre defina o intervalo de keepalive abaixo desse valor.
Um intervalo de keepalive igual ou maior que o timeout ocioso e inutil. "LB e 60s, entao ServerAliveInterval 60" ainda escorrega no limite. Mire em metade ou menos (30 ou abaixo neste exemplo).
O que usar para sobreviver a desconexoes?
Conclusao: A correcao mais profunda e tornar uma queda inofensiva. Execute
tmux/screenno servidor e sua sessao persiste mesmo quando o SSH morre -- reconecte eattachpara voltar. Em links instaveis,moshreconecta automaticamente.
Keepalive mantem voce conectado; tmux / mosh evitam que uma desconexao cause dano. Combine ambos para robustez.
# Iniciar uma sessao tmux no servidor $ tmux new -s work # Apos o SSH cair, reconecte e volte para a sessao $ ssh user@server $ tmux attach -t work
Execute processos longos e comandos arriscados dentro de tmux / screen para que uma queda de link nao derrube o processo junto. Se transferencias grandes com scp / rsync continuam falhando no meio, use rsync retomavel.
mosh (mobile shell) e baseado em UDP e recupera automaticamente entre mudancas de IP e breves interrupcoes -- ideal para links moveis ou instaveis. Requer a instalacao do mosh no servidor e a abertura de suas portas UDP.
Resumo e checklist
Conclusao: Se morre ocioso, o primeiro passo e keepalive --
ServerAliveIntervalno cliente ouClientAliveIntervalno servidor. Mantenha o intervalo abaixo de qualquer timeout ocioso de NAT / LB, e combine com tmux / mosh para que uma queda seja inofensiva. Isso resolve quase todas as desconexoes SSH inesperadas.
- [ ] Separar queda-ociosa vs queda-em-uso (silencio vs qualidade do link)
- [ ] Definir
ServerAliveInterval/ServerAliveCountMaxno~/.ssh/configdo cliente - [ ] Se voce gerencia o servidor, definir
ClientAliveIntervalem/etc/ssh/sshd_config, depoissshd -t->reload - [ ] Tornar o intervalo de keepalive confiavelmente menor que o timeout ocioso do NAT / LB
- [ ] Manter uma segunda sessao SSH aberta ao alterar configuracao para se proteger contra bloqueio
- [ ] Em links instaveis, usar tmux / screen / mosh para tolerar desconexoes
- [ ] Se ainda cair, verificar o motivo no servidor com
journalctl -u ssh