Fail2ban avançado: SSH, Nginx e APIs

A configuração padrão do fail2ban protege apenas SSH. Com filtros customizados, você protege Nginx, endpoints de login da sua API e qualquer serviço que gere logs. Este artigo vai além do básico: filtros para sua aplicação, proteção contra scanning de vulnerabilidades e operação do dia a dia.

Configuração base: jail.local

Nunca edite jail.conf, crie jail.local que sobrescreve as configurações padrão:

bash
# /etc/fail2ban/jail.local

[DEFAULT]
bantime = 3600      # ban por 1 hora
findtime = 600      # janela de 10 minutos
maxretry = 5
ignoreip = 127.0.0.1/8 ::1 SEU_IP_FIXO/32
backend = auto

[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
maxretry = 3
bantime = 86400     # 24h para SSH

Proteger Nginx: bots e brute force

Adicione jails para monitorar logs do Nginx:

bash
# /etc/fail2ban/jail.local — adicionar:

[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 5

[nginx-botsearch]
enabled = true
port = http,https
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 86400

# /etc/fail2ban/filter.d/nginx-botsearch.conf:
# [Definition]
# failregex = <HOST> .* "(GET|POST) .*\.(php|asp|aspx|cgi|env|git)
# ignoreregex =

[nginx-limit-req]
enabled = true
port = http,https
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 10

Filtro customizado para sua aplicação

Crie filtros para proteger endpoints específicos da sua API:

bash
# /etc/fail2ban/filter.d/minha-api.conf
[Definition]
failregex = ^.*"ip":"<HOST>".*"event":"login_failed".*$
            ^.*"remoteAddr":"<HOST>".*"status":401.*$

ignoreregex =

# /etc/fail2ban/jail.local:
[minha-api]
enabled = true
port = http,https
filter = minha-api
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 300

# Testar o filtro sem ban real:
fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/minha-api.conf

Comandos de operação

Gerenciar bans, ver status e desbanir IPs legítimos:

bash
# Status geral
fail2ban-client status

# Status de uma jail (com IPs banidos)
fail2ban-client status sshd

# Desbanir IP
fail2ban-client set sshd unbanip 203.0.113.10

# Banir manualmente
fail2ban-client set sshd banip 198.51.100.5

# Logs em tempo real
tail -f /var/log/fail2ban.log

# Recarregar após mudanças
fail2ban-client reload

# IPs banidos hoje
grep "Ban " /var/log/fail2ban.log | grep "$(date +%Y-%m-%d)" | wc -l

Jail recidive: aumentar ban para reincidentes

A jail recidive bane por muito mais tempo IPs que voltam após o ban inicial:

bash
# /etc/fail2ban/jail.local — adicionar:

[recidive]
enabled = true
logpath = /var/log/fail2ban.log
banaction = %(banaction_allports)s
bantime = 604800   # 7 dias
findtime = 86400   # janela de 1 dia
maxretry = 5       # 5 bans em 1 dia → 7 dias banido

# Verificar IPs em recidive
fail2ban-client status recidive

Não quer configurar manualmente?

Implante o VPS em menos de 5 minutos com a Runstack. Infraestrutura da OPEN Datacenter, com servidores em São Paulo.

Perguntas frequentes

Configure ignoreip no jail.local com IPs fixos da equipe: ignoreip = 127.0.0.1/8 IP_ESCRITORIO/32. Para IPs dinâmicos: aumente maxretry e findtime. Para desbanir emergência: fail2ban-client set JAIL unbanip IP.

Checklist: (1) fail2ban-client status JAIL mostra 0 failures? → filtro não captura; (2) fail2ban-regex LOG FILTER testa o regex; (3) tail /var/log/fail2ban.log em tempo real; (4) o logpath aponta para o arquivo correto?

Aumenta a proteção mas aumenta o risco de falso positivo. Estratégia: 1h por padrão, 24h para SSH, use a jail recidive para aumentar progressivamente para IPs que insistem.

Problema: com Docker + Nginx, o IP no log pode ser o IP interno do container. Solução: configure Nginx para logar o IP real com proxy_set_header X-Real-IP $remote_addr e log_format usando $http_x_forwarded_for.

Cobre brute force e scanning básico. Para APIs de alto tráfego combine com: rate limiting no Nginx (limit_req_zone), autenticação JWT obrigatória e Cloudflare WAF na frente.