Diagnóstico de Conectividade SSH: Guia Prático para Sysadmins
✎ Duarte Spínola | 2026-07-12
O SSH é o protocolo fundamental para administração de servidores Linux, dispositivos de rede e, cada vez mais, Windows Server com OpenSSH. Quando falha, o sysadmin perde acesso remoto e tem de recorrer à consola iLO/iDRAC ou deslocar-se fisicamente ao datacenter. As anomalias mais comuns são: impossibilidade de conectar (firewall, serviço parado, porta alterada), autenticação que falha (chaves corrompidas, known_hosts em conflito, permissões incorrectas), lentidão (DNS reverso, GSSAPI, MTU), e desligamentos inesperados (timeout, fail2ban, ClientAliveInterval). O diagnóstico começa sempre pelo modo verbose do próprio cliente SSH, que mostra exactamente em que fase a conexão falha. Referência: OpenSSH — documentação oficial.
O SSH usa a porta TCP 22 por defeito. Em ambientes hardened, é comum alterar para uma porta não-standard (ex: 2222, 10022). Isto não substitui a necessidade de firewall e fail2ban, mas reduz o ruído de bots que fazem port scan ao 22.
1. Camadas de Diagnóstico SSH
| Camada | Sintoma | Ferramenta de diagnóstico |
|---|---|---|
| Rede | Connection timeout, host unreachable | ping, tcping, nc -zv |
| Firewall | Connection refused (porta fechada) | iptables -L, ufw status, nft list ruleset |
| Serviço sshd | Connection refused (serviço parado) | systemctl status sshd, ss -tlnp |
| Autenticação (chave) | Permission denied (publickey) | ssh -v, ssh-keygen -l, permissões |
| Autenticação (password) | Permission denied (password) | ssh -v, PAM, /var/log/auth.log |
| known_hosts | WARNING: HOST IDENTIFICATION HAS CHANGED | ssh-keygen -R, verificar MITM |
| DNS reverso | Conexão demora 10-30 segundos a estabelecer | sshd_config: UseDNS, GSSAPI |
| MTU | SSH conecta mas comandos hang a meio | ping -M do -s 1472, ssh -o IPQoS |
| fail2ban | Connection refused após várias tentativas | fail2ban-client status sshd |
| Cliente | Versão incompatível, cipher mismatch | ssh -V, ssh -Q cipher |
2. Passo 1 — O Modo Verbose é a Primeira Ferramenta
O cliente SSH tem três níveis de debug que mostram exactamente o que está a acontecer em cada fase da conexão. Antes de qualquer outra coisa, correr:
ssh -v utilizador@servidor
# Nível 2 — detalhe de autenticação e chaves
ssh -vv utilizador@servidor
# Nível 3 — detalhe máximo (debug de pacotes)
ssh -vvv utilizador@servidor
O output do verbose mostra a sequência de fases. Identificar onde para:
debug1: Connecting to servidor [192.168.1.100] port 22. # 1. Rede
debug1: Connection established. # 2. TCP conectou
debug1: Local version string: OpenSSH_9.9p1 # 3. Versão do cliente
debug1: Remote protocol version 2.0, remote software # 4. Versão do servidor
debug1: SSH2_MSG_KEXINIT sent # 5. Início de negociação
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST sent # 6. Key exchange
debug1: Host ‘servidor’ is known and matches ED25519 key # 7. known_hosts OK
debug1: Authenticating that user can log in. # 8. Autenticação
debug1: Next authentication method: publickey # 9. Tentar chave
debug1: Offering public key: /home/user/.ssh/id_ed25519 # 10. Chave oferecida
debug1: Server accepts key # 11. Chave aceite
debug1: Authentication succeeded (publickey). # 12. Autenticado
| Onde para | Camada afectada | Próximo passo |
|---|---|---|
| Linha 1 (Connecting) | Rede — não chegou ao servidor | Verificar IP, rota, firewall (secção 3) |
| Linha 2 (Connection established) | TCP OK — problema é SSH | Continuar verbose |
| Linha 5-6 (KEXINIT/KEX) | Key exchange — cipher mismatch | Verificar ciphers suportados (secção 7) |
| Linha 7 (known_hosts) | Host key changed | Verificar se é legítimo (secção 5) |
| Linha 8-10 (Authenticating/publickey) | Autenticação falha | Verificar chaves e permissões (secção 4) |
| Linha 12 (Authentication succeeded) | Autenticado mas sessão hang | MTU, DNS, ou servidor (secções 6, 8) |
3. Passo 2 — Conectividade de Rede
3.1 Testar TCP à porta 22
nc -zv servidor 22
# Output OK:
# Connection to servidor 22 port [tcp/ssh] succeeded!
# Output erro:
# nc: connect to servidor port 22 (tcp) failed: Connection refused
# → Serviço sshd parado ou firewall a rejeitar
# Ou:
# nc: connect to servidor port 22 (tcp) failed: Connection timed out
# → Firewall a descartar pacotes (DROP) ou IP errado
# Alternativa com tcping (mede latência)
tcping servidor 22
3.2 Verificar se o serviço sshd está a correr
systemctl status sshd
# Verificar se está a escutar na porta 22
ss -tlnp | grep :22
# Output esperado:
# LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:((“sshd”,pid=1234,fd=3))
# LISTEN 0 128 [::]:22 [::]:* users:((“sshd”,pid=1234,fd=4))
# Se não está a escutar, iniciar serviço:
sudo systemctl start sshd
sudo systemctl enable sshd
# Verificar configuração do sshd (testar sintaxe)
sudo sshd -t
# Output vazio = configuração OK
# Output com erro = indicar linha do problema
3.3 Verificar firewall
sudo iptables -L -n | grep 22
# Procure por: ACCEPT tcp dpt:22
# UFW (Ubuntu/Debian)
sudo ufw status
# Procure por: 22/tcp ALLOW Anywhere
# Se a regra não existe, adicionar:
sudo ufw allow 22/tcp
# Ou porta custom:
sudo ufw allow 2222/tcp
# nftables (Debian 12+, RHEL 9+)
sudo nft list ruleset | grep 22
# firewalld (RHEL/Fedora/Rocky)
sudo firewall-cmd –list-services
sudo firewall-cmd –add-service=ssh –permanent
sudo firewall-cmd –reload
3.4 Verificar se a porta foi alterada
grep -i “^Port” /etc/ssh/sshd_config
# Output padrão:
# Port 22
# Se for diferente (ex: Port 2222), o cliente deve usar:
ssh -p 2222 utilizador@servidor
4. Passo 3 — Autenticação com Chaves
4.1 Verificar chaves no cliente
ls -la ~/.ssh/
# Ficheiros esperados:
# id_ed25519 — chave privada (permissões 600)
# id_ed25519.pub — chave pública (permissões 644)
# id_rsa — chave RSA (legacy, preferir ed25519)
# known_hosts — chaves de servidores conhecidos
# Verificar fingerprint da chave
ssh-keygen -l -f ~/.ssh/id_ed25519.pub
# Output:
# 256 SHA256:abc123… user@cliente (ED25519)
4.2 Verificar permissões (causa #1 de falha de chave)
chmod 700 ~/.ssh/
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/config
chmod 644 ~/.ssh/known_hosts
# No servidor — verificar permissões do authorized_keys
chmod 700 ~/.ssh/
chmod 600 ~/.ssh/authorized_keys
# Verificar dono (deve ser o próprio utilizador, não root)
chown -R $USER:$USER ~/.ssh/
O SSH é extremamente rigoroso com permissões. Se ~/.ssh/ tem permissões 777, ou se authorized_keys tem permissões 666, o sshd recusa a chave silenciosamente — não dá erro, simplesmente ignora a chave e passa para o próximo método de autenticação. O ssh -v mostra “Offering public key” mas não “Server accepts key”.
4.3 Verificar authorized_keys no servidor
cat ~/.ssh/authorized_keys
# Deve conter a chave pública do cliente:
# ssh-ed25519 AAAAC3Nz… user@cliente
# Se não está, copiar do cliente:
ssh-copy-id -i ~/.ssh/id_ed25519.pub utilizador@servidor
# Ou manualmente — no cliente:
cat ~/.ssh/id_ed25519.pub
# Copiar output, colar no servidor em ~/.ssh/authorized_keys
4.4 Debug de rejeição de chave
ssh -vvv utilizador@servidor
# Procurar estas linhas:
# debug1: Offering public key: /home/user/.ssh/id_ed25519
# debug2: we sent a publickey packet, wait for reply
# debug1: Authentications that can continue: publickey,password
# → Se “Server accepts key” não aparece, a chave não está no authorized_keys
# ou as permissões estão incorrectas
# No servidor — verificar logs de autenticação
sudo tail -f /var/log/auth.log # Debian/Ubuntu
sudo journalctl -u sshd -f # systemd
sudo tail -f /var/log/secure # RHEL/CentOS
Referência: ssh-keygen — documentação.
5. Passo 4 — Conflito known_hosts
Quando um servidor é reinstalado ou a sua chave SSH muda, o cliente recusa conectar com o erro:
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
5.1 Verificar se a mudança de chave é legítima
Antes de remover a entrada, confirmar que a mudança de chave é esperada:
- O servidor foi reinstalado? Sim → legítimo
- O IP foi reatribuído a outro servidor? Sim → legítimo
- Nenhuma das anteriores → investigar (possível MITM)
5.2 Remover entrada antiga
ssh-keygen -R servidor
# Output:
# /home/user/.ssh/known_hosts updated.
# Original contents retained as /home/user/.ssh/known_hosts.old
# Reconectar — vai pedir para aceitar a nova chave
ssh utilizador@servidor
# The authenticity of host ‘servidor’ can’t be established.
# ED25519 key fingerprint is SHA256:xyz789…
# Are you sure you want to continue connecting (yes/no)? yes
Se a mudança de chave não é esperada, não aceitar a nova chave sem verificar com o administrador do servidor. Pode ser um ataque man-in-the-middle. Verificar a fingerprint do servidor através de canal seguro (consola iLO, telefone, etc.).
6. Passo 5 — Lentidão ao Estabelecer Conexão
6.1 DNS reverso (causa mais comum)
Por defeito, o sshd tenta resolver o IP do cliente para um nome (DNS reverso). Se o DNS reverso falha ou é lento, a conexão demora 10-30 segundos antes de pedir a password.
sudo sshd -t # testar config
sudo nano /etc/ssh/sshd_config
# Adicionar ou alterar:
UseDNS no
# Reiniciar sshd
sudo systemctl restart sshd
# Testar do cliente — deve conectar instantaneamente
time ssh utilizador@servidor exit
6.2 GSSAPI (segunda causa mais comum)
O GSSAPI (Kerberos) tenta autenticar via Kerberos antes de tentar chaves/password. Se não há Kerberos, timeout.
ssh -o GSSAPIAuthentication=no utilizador@servidor
# Ou permanentemente em ~/.ssh/config:
# Host *
# GSSAPIAuthentication no
6.3 Verificar tempo de conexão
time ssh -o ConnectTimeout=10 utilizador@servidor exit
# Decompor as fases:
ssh -v -o GSSAPIAuthentication=no -o UseDNS=no utilizador@servidor exit 2>&1 | \
awk ‘/debug1:/{print strftime(“%H:%M:%S”), $0}’
6.4 Desactivar features desnecessárias
Host *
GSSAPIAuthentication no
GSSAPIDelegateCredentials no
UseDNS no # apenas afecta o cliente se fizer reverse lookup
PreferredAuthentications publickey
Compression yes # útil em WAN lenta
ServerAliveInterval 60
ServerAliveCountMax 3
Referência: ssh_config — documentação.
7. Passo 6 — MTU e Sessões que Hang
O SSH conecta mas comandos hang a meio da execução — especialmente em VPNs, túneis, ou ligações WAN com MTU reduzido. O TCP handshake passa (pacotes pequenos) mas comandos com output grande (ex: ls -la, cat ficheiro) hang porque os pacotes grandes são dropped.
7.1 Diagnosticar MTU
ping -M do -s 1472 servidor
# 1472 = MTU 1500 – 28 bytes (IP+ICMP headers)
# Se falhar, reduzir:
ping -M do -s 1400 servidor
ping -M do -s 1300 servidor
# Quando encontra o maior que passa, usar no SSH:
ssh -o IPQoS=throughput -o [email protected] utilizador@servidor
# Ou definir MSS no cliente:
ssh -o ProxyCommand=”nc -M 1300 %h %p” utilizador@servidor
7.2 Desactivar compressão (piora em MTU baixo)
ssh -o Compression=no utilizador@servidor
8. Passo 7 — Desligamentos Inesperados
8.1 Timeout do servidor (ClientAliveInterval)
grep -i “ClientAlive” /etc/ssh/sshd_config
# Output comum:
# ClientAliveInterval 300 # 5 minutos
# ClientAliveCountMax 3 # 3 tentativas = 15 minutos total
# Se ClientAliveInterval é muito baixo, a sessão desliga por inactividade
# Aumentar:
sudo sed -i ‘s/^ClientAliveInterval.*/ClientAliveInterval 600/’ /etc/ssh/sshd_config
sudo systemctl restart sshd
8.2 Keepalive do cliente
ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 utilizador@servidor
# Ou em ~/.ssh/config:
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
8.3 fail2ban a bloquear
O fail2ban bloqueia IPs após várias tentativas falhadas. Se o utilizador tenta conectar com chave errada várias vezes, o IP é banido.
sudo fail2ban-client status sshd
# Output:
# Banned IP list: 192.168.1.50
# Desbloquear IP manualmente
sudo fail2ban-client set sshd unbanip 192.168.1.50
# Verificar regras de iptables criadas pelo fail2ban
sudo iptables -L f2b-sshd -n
8.4 TCP wrappers (hosts.deny)
cat /etc/hosts.deny | grep -i ssh
cat /etc/hosts.allow | grep -i ssh
# Se hosts.deny tem:
# sshd: ALL
# E hosts.allow não tem excepção para o IP, todas as conexões são recusadas
9. Passo 8 — Logs do Servidor
9.1 Ver logs de autenticação
sudo tail -f /var/log/auth.log | grep ssh
# RHEL/CentOS/Rocky
sudo tail -f /var/log/secure | grep ssh
# systemd (qualquer distro)
sudo journalctl -u sshd -f
sudo journalctl -u ssh -f
# Procurar tentativas falhadas
sudo journalctl -u sshd –since “1 hour ago” | grep -i “failed\|invalid\|refused”
9.2 Mensagens comuns nos logs
| Mensagem | Significado | Solução |
|---|---|---|
Connection from X port Y |
Conexão recebida | Normal |
Failed publickey for user from X |
Chave rejeitada | Verificar authorized_keys e permissões |
Invalid user user from X |
Utilizador não existe | Verificar nome de utilizador |
Connection closed by X |
Cliente desligou | Normal se intencional |
Connection reset by X |
Rede cortou | Verificar firewall/VPN |
error: kex_exchange_identification |
Banner exchange falhou | Versão SSH incompatível ou rede |
refused connect from X |
TCP wrappers bloqueou | Verificar hosts.deny |
max startups |
Demasiadas conexões simultâneas | Aumentar MaxStartups em sshd_config |
9.3 Aumentar logging do sshd para diagnóstico
sudo sed -i ‘s/^#LogLevel.*/LogLevel DEBUG3/’ /etc/ssh/sshd_config
sudo systemctl restart sshd
# Reproduzir o problema
# Analisar logs
sudo journalctl -u sshd –since “5 min ago” –no-pager
# Restaurar para INFO quando terminar
sudo sed -i ‘s/^LogLevel DEBUG3/LogLevel INFO/’ /etc/ssh/sshd_config
sudo systemctl restart sshd
Referência: sshd_config — documentação.
10. Passo 9 — SSH em Windows
10.1 OpenSSH no Windows Server
Get-WindowsCapability -Online | Where-Object Name -like “OpenSSH.Server*”
# Instalar
Add-WindowsCapability -Online -Name “OpenSSH.Server~~~~0.0.1.0”
# Iniciar e activar serviço
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
# Verificar firewall
Get-NetFirewallRule -Name *ssh*
# Se não existe regra, criar:
New-NetFirewallRule -Name sshd -DisplayName “OpenSSH Server” -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
Referência: OpenSSH no Windows — Microsoft Learn.
10.2 Chaves em Windows
ssh-keygen -t ed25519
# As chaves ficam em:
# C:\Users\utilizador\.ssh\id_ed25519
# C:\Users\utilizador\.ssh\id_ed25519.pub
# authorized_keys em Windows Server (admin):
# C:\ProgramData\ssh\administrators_authorized_keys
# Permissões: apenas SYSTEM e Administrators
# authorized_keys em Windows Server (user normal):
# C:\Users\utilizador\.ssh\authorized_keys
Em Windows, as permissões de authorized_keys são diferente. Para administradores, o ficheiro fica em C:\ProgramData\ssh\administrators_authorized_keys e deve ter permissões apenas para SYSTEM e Administrators. Se um utilizador normal tiver permissão de escrita, o sshd ignora a chave.
11. Erros Comuns e Resolução
- “Connection refused” — serviço sshd parado ou porta incorrecta. Verificar
systemctl status sshdess -tlnp | grep :22. - “Connection timed out” — firewall a descartar pacotes (DROP) ou IP errado. Verificar
iptables -L -n,ufw status. - “Permission denied (publickey)” — chave não está no
authorized_keys, permissões incorrectas em~/.ssh/ouauthorized_keys, ou chave privada errada. Usarssh -vvvpara ver qual chave é oferecida e se é aceite. - “REMOTE HOST IDENTIFICATION HAS CHANGED” — chave do servidor mudou. Confirmar se é legítimo e usar
ssh-keygen -R servidor. - “No route to host” — IP errado, gateway em falta, ou VPN desconectada. Verificar
ip routeeping gateway. - SSH demora 20-30 segundos a conectar — DNS reverso ou GSSAPI. Desactivar
UseDNS nono servidor eGSSAPIAuthentication nono cliente. - SSH conecta mas comandos hang — problema de MTU. Testar com
ping -M do -s 1472e reduzir MTU se necessário. - “Bad permissions” (Windows) —
authorized_keyscom permissões incorrectas. Usaricaclspara restringir a SYSTEM e Administrators. - Sessão desliga por inactividade —
ClientAliveIntervalno servidor ouServerAliveIntervalno cliente. Configurar keepalive. - “Too many authentication failures” — cliente tem demasiadas chaves e todas são tentadas antes da correcta. Usar
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519para forçar apenas uma chave. - “no matching cipher found” — cliente e servidor não têm ciphers em comum. Verificar
ssh -Q cipherno cliente eCiphersemsshd_configno servidor. - fail2ban bloqueia repetidamente — chave SSH incorrecta ou password errada a falhar. Verificar
fail2ban-client status sshde desbloquear comfail2ban-client set sshd unbanip <IP>.
12. Checklist de Diagnóstico
- Modo verbose —
ssh -vvv utilizador@servidorpara identificar a fase que falha - Rede —
nc -zv servidor 22para testar TCP à porta SSH - Serviço —
systemctl status sshdess -tlnp | grep :22no servidor - Firewall —
iptables -L,ufw status, oufirewall-cmd --list-services - Porta — verificar
Portemsshd_configse não é a padrão 22 - Permissões —
chmod 700 ~/.ssh/,chmod 600 authorized_keysno servidor - Chave —
ssh-keygen -l -f ~/.ssh/id_ed25519.pubpara verificar fingerprint - authorized_keys — confirmar que a chave pública está no servidor
- known_hosts —
ssh-keygen -R servidorse a chave do servidor mudou - DNS reverso —
UseDNS nono servidor se conexão é lenta - GSSAPI —
ssh -o GSSAPIAuthentication=nose conexão é lenta - MTU —
ping -M do -s 1472 servidorse sessões hang - Logs —
journalctl -u sshd -fou/var/log/auth.logpara erros - Keepalive —
ServerAliveInterval 60no cliente para evitar desligamentos - fail2ban —
fail2ban-client status sshdse IP foi bloqueado