Fail2ban: Proteger SSH e Serviços Linux contra Ataques de Força Bruta em 2026
Linux · Segurança · Fail2ban · SSH · Brute Force · Nftables | ✎ Duarte Spínola | 10 de Julho de 2026
O fail2ban é a ferramenta padrão para protecção automática contra ataques de força bruta em servidores Linux. Monitoriza ficheiros de log, detecta padrões de autenticação falhada, e bloqueia automaticamente os IPs ofensivos no firewall. Este guia cobre a instalação, configuração de jails para SSH, Nginx, Apache, e serviços custom, tuning de thresholds para PME, integração com nftables/iptables, e diagnóstico de problemas. Inclui comandos testados em Ubuntu 24.04, Debian 12, RHEL 9 e CentOS Stream 9.
Conteúdos
- 1. O que Está a Acontecer — Ameaças de Força Bruta em 2026
- 2. Cenários em que o Fail2ban é Essencial
- 3. Instalar e Configurar o Fail2ban
- 4. Jail SSH — Configuração Detalhada
- 5. Jails para Nginx, Apache e Outros Serviços
- 6. Configuração Avançada — Jails Custom e Regex
- 7. Integração com Nftables e IPTables
- 8. Whitelist, Persistência e Recidive
- 9. Diagnóstico e Troubleshooting
- 10. Alternativas — CrowdSec e SSHGuard
- 11. FAQ para Sysadmins
- 12. Erros Comuns e Resoluções
1. O que Está a Acontecer — Ameaças de Força Bruta em 2026
Ataques de força bruta contra serviços expostos — especialmente SSH — são constantes e automatizados. Bots percorrem ranges inteiros de IPs à procura de servidores com a porta 22 aberta, e tentam milhares de combinações de utilizador/password por minuto. O MITRE ATT&CK cataloga este vector como T1110.004 (Brute Force: SSH) (MITRE ATT&CK T1110.004).
Num servidor cloud típico (Hetzner, DigitalOcean, AWS) recém-criado com SSH na porta 22 e autenticação por password activa, as primeiras tentativas de brute-force aparecem em menos de 5 minutos. Um servidor sem protecção pode receber 10.000+ tentativas por dia.
O fail2ban resolve este problema de forma automática: lê os logs de autenticação em tempo real, identifica IPs com múltiplas falhas, e adiciona regras de firewall para os bloquear temporariamente. É a primeira linha de defesa, complementar a chaves SSH e hardening do sshd_config (fail2ban GitHub, Arch Wiki — Fail2ban).
⚠ Fail2ban não substitui hardening. Desactivar PasswordAuthentication no sshd_config continua a ser a medida mais eficaz. O fail2ban é uma camada adicional — reduz ruído nos logs, bloqueia bots ruidosos, e protege serviços que não suportam chaves (web apps, painéis de controlo, FTP).
2. Cenários em que o Fail2ban é Essencial
| Cenário | Risco | Jail recomendada |
|---|---|---|
| Servidor cloud com SSH na porta 22 | Brute force SSH constante | sshd (jail padrão) |
| Servidor web com Nginx/Apache | Ataques a wp-login.php, /admin, .htaccess | nginx-limit-req, nginx-botsearch |
| Servidor de email (Postfix/Dovecot) | Brute force SMTP/IMAP | postfix, dovecot |
| FTP/SFTP server (vsftpd, proftpd) | Brute force FTP | vsftpd, proftpd |
| Painel de controlo (cPanel, Plesk) | Ataques ao login do painel | Jail custom com regex específica |
| VPN server (OpenVPN, WireGuard) | Tentativas de ligação inválidas | Jail custom para OpenVPN log |
| Servidor com múltiplos serviços | Vários vectores de ataque | Múltiplas jails + recidive para reincidentes |
| PME com IPs fixos de funcionários | Bloquear IPs legítimos por engano | Whitelist de IPs da empresa |
3. Instalar e Configurar o Fail2ban
Instalação
# Ubuntu / Debian sudo apt update sudo apt install fail2ban # RHEL / CentOS Stream / Rocky / Alma sudo dnf install fail2ban # O EPEL é necessário em RHEL: # sudo dnf install epel-release && sudo dnf install fail2ban # Verificar versão fail2ban-client --version # Fail2Ban v1.1.0
Estrutura de ficheiros
# NUNCA editar jail.conf directamente — criar jail.local
/etc/fail2ban/
├── jail.conf # Configuração padrão (NÃO EDITAR — perde-se em updates)
├── jail.local # Override local (criar aqui)
├── fail2ban.local # Override do daemon
├── filter.d/ # Filtros regex por serviço
│ ├── sshd.conf # Filtro para SSH
│ ├── nginx-http-auth.conf
│ ├── apache-auth.conf
│ └── ...
├── action.d/ # Acções (iptables, nftables, etc.)
│ ├── iptables-multiport.conf
│ ├── nftables-multiport.conf
│ └── ...
└── paths/
└── debian.conf # Caminhos de logs por distro
Configuração base — jail.local
# Criar jail.local sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local # OU criar do zero (mais limpo): sudo tee /etc/fail2ban/jail.local << 'EOF' [DEFAULT] # Tempo de banimento (segundos) — 1 hora por defeito bantime = 3600 # Tempo de busca de falhas (segundos) — 10 minutos findtime = 600 # Número de falhas antes de banir maxretry = 3 # Whitelist — IPs que nunca são banidos ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 10.0.0.0/8 # Acção padrão: banir no firewall + email # Para PME sem email: usar apenas firewall banaction = nftables-multiport # banaction = iptables-multiport (alternativa) # Email (opcional) # destemail = [email protected] # sender = [email protected] # action = %(action_)s # Backend de logs backend = systemd [sshd] enabled = true port = ssh filter = sshd logpath = %(sshd_log)s maxretry = 3 bantime = 3600 EOF # Reiniciar sudo systemctl restart fail2ban sudo systemctl enable fail2ban # Verificar sudo fail2ban-client status # Status # |- Number of jail: 1 # `- Jail list: sshd
4. Jail SSH — Configuração Detalhada
Configuração recomendada para PME
# /etc/fail2ban/jail.local — secção [sshd] [sshd] enabled = true port = ssh filter = sshd logpath = %(sshd_log)s backend = systemd # 3 tentativas falhadas em 10 minutos = ban maxretry = 3 findtime = 600 # Ban de 1 hora para primeira infração bantime = 3600 # Ban progressivo para reincidentes # Usa a jail recidive (ver secção 8) bantime.increment = true bantime.factor = 2 bantime.maxtime = 604800 # máximo 1 semana
Verificar a jail SSH
# Status da jail sudo fail2ban-client status sshd # Output: # Status for the jail: sshd # |- Filter # | |- Currently failed: 0 # | |- Total failed: 47 # | `- File list: /var/log/auth.log # `- Actions # |- Currently banned: 2 # |- Total banned: 15 # `- Banned IP list: 1.2.3.4 5.6.7.8 # Ver IPs banidos sudo fail2ban-client status sshd | grep "Banned IP" # Ver logs do fail2ban sudo journalctl -u fail2ban -f # ou sudo tail -f /var/log/fail2ban.log
Desbanir um IP manualmente
# Desbanir IP específico sudo fail2ban-client set sshd unbanip 1.2.3.4 # Adicionar IP à whitelist permanentemente sudo fail2ban-client set sshd addignoreip 192.168.1.50 # Verificar se IP está banido sudo fail2ban-client status sshd | grep 1.2.3.4
5. Jails para Nginx, Apache e Outros Serviços
Nginx — Proteger wp-login.php e .htaccess
# /etc/fail2ban/jail.local — adicionar: [nginx-http-auth] enabled = true port = http,https filter = nginx-http-auth logpath = /var/log/nginx/error.log maxretry = 3 bantime = 3600 [nginx-botsearch] enabled = true port = http,https filter = nginx-botsearch logpath = /var/log/nginx/access.log maxretry = 2 bantime = 7200 [nginx-limit-req] enabled = true port = http,https filter = nginx-limit-req logpath = /var/log/nginx/error.log maxretry = 5 findtime = 600 bantime = 7200
Apache — Proteger login e directory traversal
# /etc/fail2ban/jail.local — adicionar: [apache-auth] enabled = true port = http,https filter = apache-auth logpath = /var/log/apache2/error.log maxretry = 3 bantime = 3600 [apache-botsearch] enabled = true port = http,https filter = apache-botsearch logpath = /var/log/apache2/access.log maxretry = 2 bantime = 7200 [apache-overflows] enabled = true port = http,https filter = apache-overflows logpath = /var/log/apache2/error.log maxretry = 2 bantime = 3600
Postfix / Dovecot — Email
# /etc/fail2ban/jail.local — adicionar: [postfix] enabled = true port = smtp,submissions filter = postfix logpath = /var/log/mail.log maxretry = 3 bantime = 3600 [dovecot] enabled = true port = pop3,pop3s,imap,imaps filter = dovecot logpath = /var/log/mail.log maxretry = 3 bantime = 3600
6. Configuração Avançada — Jails Custom e Regex
Criar um filtro customizado
Se tem uma aplicação custom que gera logs de autenticação, pode criar um filtro regex dedicado:
# /etc/fail2ban/filter.d/myapp.conf [Definition] # Regex para linhas de log com auth falhada failregex = ^.*AUTH FAILED.*from <HOST>.*$ # Regex para ignorar (linhas legítimas) ignoreregex = # Testar o filtro contra um ficheiro de log sudo fail2ban-regex /var/log/myapp.log /etc/fail2ban/filter.d/myapp.conf # Output esperado: # Lines: 1245 lines, 0 ignored, 47 matched, 1198 missed # Success - 47 matches
Jail para a aplicação custom
# /etc/fail2ban/jail.local [myapp] enabled = true port = 8080 filter = myapp logpath = /var/log/myapp.log maxretry = 5 findtime = 300 bantime = 3600 banaction = nftables-multiport
7. Integração com Nftables e IPTables
Nftables (recomendado em 2026)
Em Ubuntu 24.04, Debian 12, e RHEL 9, o nftables é o backend de firewall padrão, substituindo o iptables. O fail2ban suporta nftables nativamente:
# /etc/fail2ban/jail.local — usar nftables
[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables-allports
# Verificar que nftables está activo
sudo nft list ruleset | grep fail2ban
# Deve mostrar chains do fail2ban
# As regras criadas pelo fail2ban aparecem como:
# table inet f2b-table {
# set addr-set-sshd { ... }
# chain f2b-sshd { ... }
# }
IPTables (legacy)
# /etc/fail2ban/jail.local — usar iptables [DEFAULT] banaction = iptables-multiport banaction_allports = iptables-allports # Verificar regras criadas sudo iptables -L -n | grep f2b # Chain f2b-sshd (1 references) # DROP all -- 1.2.3.4 0.0.0.0/0
ℹ Não misture iptables e nftables. Se o seu sistema usa nftables por defeito (Ubuntu 24.04+), configure o fail2ban com banaction = nftables-multiport. Usar iptables pode criar conflitos ou regras que não são aplicadas.
8. Whitelist, Persistência e Recidive
Whitelist de IPs
# /etc/fail2ban/jail.local — secção [DEFAULT]
[DEFAULT]
# IPs que nunca são banidos (separados por espaço)
ignoreip = 127.0.0.1/8 ::1
192.168.1.0/24 # rede local da empresa
10.0.0.0/8 # VPN interna
203.0.113.50 # IP fixo do admin remoto
198.51.100.0/28 # range do escritório remoto
# Adicionar dinamicamente (sem reiniciar)
sudo fail2ban-client set sshd addignoreip 203.0.113.100
# Remover
sudo fail2ban-client set sshd delignoreip 203.0.113.100
Ban progressivo (recidive)
A jail recidive aumenta o tempo de banimento para IPs que são banidos repetidamente — um IP que foi banido 3 vezes recebe um banimento longo (por defeito, 1 semana):
# /etc/fail2ban/jail.local [recidive] enabled = true filter = recidive logpath = /var/log/fail2ban.log maxretry = 3 findtime = 86400 # 24 horas bantime = 604800 # 1 semana # Ban progressivo na jail sshd [sshd] enabled = true bantime.increment = true bantime.factor = 2 # dobra a cada infração bantime.maxtime = 604800 # máximo 1 semana
Persistência de bans
Por defeito, os bans do fail2ban são perdidos quando o serviço reinicia. Para manter bans entre reinícios:
# /etc/fail2ban/fail2ban.local [Definition] # Base de dados SQLite para persistir bans dbfile = /var/lib/fail2ban/fail2ban.sqlite3 dbpurgeage = 604800 # purgar bans antigos após 1 semana
9. Diagnóstico e Troubleshooting
Verificar se o fail2ban está a funcionar
# Estado geral sudo fail2ban-client status # Estado de uma jail específica sudo fail2ban-client status sshd # Logs em tempo real sudo journalctl -u fail2ban -f # Verificar configuração sudo fail2ban-client -t # OK: configuration test succeeded
Testar um filtro contra um log real
# Testar filtro sshd contra o auth.log sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf # Output: # Lines: 5234 lines, 0 ignored, 89 matched, 5145 missed # Success - 89 matches (1.7% of lines) # Testar com um log customizado sudo fail2ban-regex /var/log/myapp.log /etc/fail2ban/filter.d/myapp.conf --print-all-matched
Forçar um ban manualmente (teste)
# Banir IP manualmente sudo fail2ban-client set sshd banip 1.2.3.4 # Verificar sudo fail2ban-client status sshd | grep 1.2.3.4 # Desbanir sudo fail2ban-client set sshd unbanip 1.2.3.4
Problema: fail2ban não detecta falhas
# 1. Verificar que o ficheiro de log está correcto sudo fail2ban-client get sshd logpath # /var/log/auth.log # 2. Verificar que o log tem entradas de falha sudo grep "Failed password" /var/log/auth.log | tail -5 # 3. Verificar que o filtro faz match sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf # 4. Se backend=systemd, verificar journal sudo journalctl -u ssh -n 20 | grep "Failed" # 5. Verificar timezone (logs vs sistema) date sudo fail2ban-client get sshd datepattern
10. Alternativas — CrowdSec e SSHGuard
O fail2ban não é a única opção. Duas alternativas modernas:
| Ferramenta | Vantagens | Desvantagens |
|---|---|---|
| fail2ban | Standard, simples, milhares de filtros prontos, comunidade enorme | Sem threat intelligence, bloqueia por IP individual apenas |
| CrowdSec | Threat intelligence partilhada (community blocklist), arquitetura moderna, suporta remediação (captcha, MFA) | Mais complexo, requer registo para blocklist, menor comunidade |
| SSHGuard | Extremamente leve, foco em SSH, configuração minimalista | Menos filtros prontos, sem interface de gestão, menos flexível |
Quando usar cada um:
- fail2ban — PME com 1-10 servidores, simplicidade, sem dependências externas
- CrowdSec — PME com múltiplos servidores que beneficia de threat intelligence partilhada ( IPs maliciosos já detectados por outros são bloqueados automaticamente)
- SSHGuard — Edge/IoT com recursos limitados, apenas SSH para proteger
11. FAQ para Sysadmins
1. Fail2ban protege contra ataques distribuídos (distributed brute force)?
Parcialmente. Se o atacante usa 1000 IPs diferentes com 1 tentativa cada, o maxretry=3 nunca é atingido por IP. Para este cenário, o CrowdSec é mais eficaz (blocklist partilhada detecta IPs maliciosos conhecidos). O fail2ban é optimizado para bots ruidosos de um único IP.
2. Quanto tempo de banimento usar?
1 hora para primeira infração é o padrão. Use ban progressivo (bantime.increment = true) para que reincidentes recebam bans cada vez mais longos. Para bots persistentes, a jail recidive com 1 semana é eficaz.
3. O fail2ban consome muitos recursos?
Não. Tipicamente < 1% CPU e < 50MB RAM. Usa Python + regex sobre logs, não captura tráfego de rede. Em Raspberry Pi com fail2ban a monitorizar SSH, o impacto é negligenciável.
4. Posso ter fail2ban e CrowdSec ao mesmo tempo?
Tecnicamente sim, mas não é recomendado — ambos vão tentar bloquear os mesmos IPs e podem criar conflitos no firewall. Escolha um. Se precisa de ambos, use fail2ban para detecção local e CrowdSec para blocklist global.
5. Como evitar bloquear IPs legítimos?
Whitelist (ignoreip) de todos os IPs fixos da empresa, VPN, e administradores remotos. Se um IP legítimo for bloqueado, desbane com sudo fail2ban-client set sshd unbanip IP e adicione à whitelist.
6. Fail2ban funciona com Docker?
Sim, mas precisa de configuração adicional. Se o SSH corre dentro de um container, o fail2ban no host precisa de aceder aos logs do container. Alternativa: instalar fail2ban dentro do container (não recomendado para containers efémeros) ou usar Docker logging driver para enviar logs para o host.
7. O que é backend = systemd?
Em vez de ler ficheiros de log (/var/log/auth.log), o fail2ban lê directamente do journalctl via systemd. É mais eficiente e funciona em sistemas que não mantêm ficheiros de log persistentes (journald apenas).
8. Como ver estatísticas de longo prazo?
# Total de bans por jail
sudo fail2ban-client status sshd | grep "Total banned"
# Histórico de bans no log
sudo grep "Ban" /var/log/fail2ban.log | awk '{print $NF}' | sort | uniq -c | sort -rn | head -20
# Top 20 IPs mais banidos
sudo grep "Ban" /var/log/fail2ban.log | grep -oP '\d+\.\d+\.\d+\.\d+' | sort | uniq -c | sort -rn | head -20
12. Erros Comuns e Resoluções
| Sintoma | Causa | Solução |
|---|---|---|
| fail2ban-client: command not found | Não instalado | sudo apt install fail2ban |
| Number of jail: 0 | Nenhuma jail activada | Verificar enabled = true em jail.local |
| Total failed: 0 | Logpath errado ou backend incorrecto | Verificar logpath ou usar backend = systemd |
| Currently banned: 0 mas há falhas no log | Filtro regex não faz match | fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf |
| Have not found any log file for sshd jail | Caminho do log inexistente | Verificar se /var/log/auth.log existe ou usar backend = systemd |
| IP banido mas ainda consegue ligar | Firewall backend errado (iptables vs nftables) | Verificar banaction corresponde ao firewall activo |
| Bans desaparecem após reiniciar | Sem base de dados de persistência | Verificar dbfile em fail2ban.local |
| Configuration test failed | Erro de sintaxe em jail.local | sudo fail2ban-client -t mostra o erro |
| SSHGuard vs Fail2ban conflito | Ambos a gerir firewall | Usar apenas um de cada vez |
| ignoreip não funciona | Sintaxe incorrecta ou na secção errada | Colocar ignoreip em [DEFAULT], separar IPs por espaço |
Artigos Relacionados
- SSH: Configuração, Hardening e Diagnóstico para Sysadmins
- Gestão de Utilizadores e Sudo em Linux
- Configuração e Diagnóstico de NIC em Linux
- Diagnóstico de Conectividade Linux Avançado
- NIS2 em 2026: Checklist em 90 Dias para Sysadmins
- Plano de Resposta a Ransomware para Empresas Portuguesas
- Diagnóstico de Kernel Logs Linux
