Troubleshooting real: do crash status 255 no Fail2ban ao backend systemd e modularização no Nginx
Voltar para blog

Troubleshooting real: do crash status 255 no Fail2ban ao backend systemd e modularização no Nginx

Atualizado em 20/09/2026 · Publicado em 26/10/2026 · 6 min · Cibersegurança

Problemas de inicialização de serviços no Linux frequentemente revelam incompatibilidades entre transições de arquitetura de logging e peculiaridades de permissão no sistema de arquivos.

Recentemente, passei por esse cenário: o serviço do Fail2Ban recusava-se a subir após uma inicialização, abortando com um código de erro fatal. Em seguida, precisei estruturar a inclusão modular de regras externas tanto no Fail2Ban quanto no Nginx.

Abaixo, compartilho o passo a passo da análise forense, os comandos executados no terminal e as soluções definitivas adotadas.


1. O problema inicial: code=exited, status=255/EXCEPTION#

Ao checar o status do serviço Fail2Ban no servidor:

service fail2ban status

O systemd retornou o seguinte diagnóstico:

× fail2ban.service - Fail2Ban Service
     Loaded: loaded (/lib/systemd/system/fail2ban.service; enabled; preset: enabled)
     Active: failed (Result: exit-code) since Sat 2026-04-04 07:38:19 -03; 1s ago
   Duration: 137ms
       Docs: man:fail2ban(1)
    Process: 220018 ExecStart=/usr/bin/fail2ban-server -xf start (code=exited, status=255/EXCEPTION)
   Main PID: 220018 (code=exited, status=255/EXCEPTION)
        CPU: 95ms

O que significa o status 255 no Fail2ban?#

O binário /usr/bin/fail2ban-server é uma aplicação Python. Quando ele retorna o código 255/EXCEPTION em meros 137ms, significa que o interpretador levantou uma exceção crítica ainda durante o bootstrap (leitura de configurações, inicialização do socket IPC ou abertura do banco SQLite), antes mesmo de estabelecer o loop principal do daemon.


2. Inspeção forense dos logs com journalctl#

Como a saída padrão do systemctl status trunca as linhas longas, filtrei o journal diretamente pelo PID do processo que falhou (PID 220018):

journalctl _PID=220018 --no-pager

A saída revelou a causa exata:

Apr 04 07:38:19 srv01.domain.com.br fail2ban-server[220018]: 2026-04-04 07:38:19,909 fail2ban.configreader   [220018]: WARNING 'allowipv6' not defined in 'Definition'. Using default one: 'auto'
Apr 04 07:38:19 srv01.domain.com.br fail2ban-server[220018]: 2026-04-04 07:38:19,917 fail2ban                [220018]: ERROR   Failed during configuration: Have not found any log file for sshd jail
Apr 04 07:38:19 srv01.domain.com.br fail2ban-server[220018]: 2026-04-04 07:38:19,923 fail2ban                [220018]: ERROR   Async configuration of server failed

A raiz do problema estava explícita: Have not found any log file for sshd jail.


3. Investigando o sistema de arquivos e o fluxo de logs#

Executei três verificações rápidas no host:

1. Checagem do arquivo padrão de autenticação#

ls -l /var/log/auth.log
# Retorno: ls: cannot access '/var/log/auth.log': No such file or directory

2. Checagem dos logs do OpenSSH via journald#

journalctl -u ssh | head -n 5

Os eventos do SSH existiam e estavam sendo registrados normalmente no Journal do Systemd.

3. Dump da interpretação de configuração do Fail2Ban#

fail2ban-client -d | grep -A 5 "\[sshd\]"

O diagnóstico#

O host roda uma distribuição Linux moderna onde o systemd-journald gerencia os logs nativamente, sem um daemon clássico de rsyslog gravando arquivos de texto em /var/log/auth.log.

Por padrão, a jail [sshd] do Fail2Ban procura por arquivos físicos via polling de texto. Como o caminho definido em logpath não existia no disco, o leitor de jails lançou uma exceção fatal e derrubou o processo.


4. A solução definitiva: migrando para o backend = systemd#

Em vez de instalar pacotes legados de syslog ou criar arquivos de texto artificiais, a solução correta é instruir o Fail2Ban a consumir os eventos diretamente da API binária do systemd-journald.

Editei o arquivo /etc/fail2ban/jail.local:

[DEFAULT]
# Define o systemd journal como backend global
backend = systemd

[sshd]
enabled = true
# Com backend = systemd, o logpath e ignorado; o filtro usa journalmatch com _COMM=sshd e _SYSTEMD_UNIT (ssh.service no Debian/Ubuntu, sshd.service no RHEL/CentOS)

Vantagens do backend systemd#

Nota: Certifique-se de que os bindings do Python para o Systemd estejam instalados (apt install python3-systemd em sistemas Debian/Ubuntu, ou dnf install python3-systemd no RHEL).

Validei e iniciei o serviço:

fail2ban-client -t
systemctl restart fail2ban
fail2ban-client status sshd

Matriz de Diagnóstico: Qual backend de logging utilizar no Fail2ban?#

BackendMétodo de CapturaDepende de /var/log?Consumo de CPUCompatibilidade Moderna
pollingLê periodicamente arquivos de texto em /var/log/✅ Sim (Crash 255 se faltar)Médio / Alto⚠️ Legado (Distros antigas com rsyslog ativo)
pyinotifyNotificações de eventos via syscall inotify✅ SimBaixo⚠️ Requer biblioteca Python de terceiros
systemdConsulta direta à API do Journal via python3-systemd❌ Não (Lê do Journal)Mínimo🏆 Recomendado (Debian 12+, Ubuntu 24.04+, RHEL 9+)

5. Modularização de regras externas no Fail2ban e Nginx#

Durante a manutenção, estruturei a inclusão de arquivos externos de regras personalizadas (rules.conf) tanto no Fail2Ban quanto no Nginx.

A. Modularização no Fail2ban#

No Fail2Ban, existem duas abordagens recomendadas para modularizar configurações:

Método 1: Diretório nativo /etc/fail2ban/jail.d/*.conf (idiomático e recomendado)#

A forma mais limpa e padrão no Fail2Ban é criar arquivos .conf dedicados dentro do diretório /etc/fail2ban/jail.d/ (por exemplo, /etc/fail2ban/jail.d/rules.conf). O Fail2Ban processa automaticamente todos os arquivos desse diretório em ordem alfabética após ler o jail.conf e o jail.local, sobrescrevendo parâmetros sem a necessidade de editar arquivos centrais:

# /etc/fail2ban/jail.d/rules.conf
[DEFAULT]
backend = systemd
findtime = 600
bantime = 3600
maxretry = 5

[sshd]
enabled = true

Método 2: Diretiva [INCLUDES] no jail.local#

Caso queira incluir um arquivo explicitamente antes da leitura das seções principais, use a diretiva [INCLUDES] no topo de /etc/fail2ban/jail.local. Como o Fail2Ban resolve caminhos relativos a partir do próprio diretório de configuração (/etc/fail2ban/), o arquivo deve residir em /etc/fail2ban/rules.conf:

# /etc/fail2ban/jail.local
[INCLUDES]
before = rules.conf

Validação da leitura das regras combinadas:

fail2ban-client -d | grep -A 10 "\[sshd\]"

B. Modularização no Nginx#

No Nginx, a sintaxe utiliza a diretiva include com ponto e vírgula obrigatório:

server {
    listen 80;
    server_name domain.com.br;

    # Importacao de regras customizadas
    include /path/to/project/rules.conf;
}

Permissões de diretório e travessia (bit +x)#

O processo Master do Nginx roda como root, mas os processos Worker rodam como www-data ou nginx. Para que arquivos em diretórios aninhados sejam lidos sem erros de Permission Denied (EACCES), todas as pastas pais precisam do bit de execução (+x):

namei -l /path/to/project/rules.conf

Validação e teste#

Sempre teste a sintaxe antes de recarregar:

nginx -t

# Visualizar a configuracao completa expandida em memoria
nginx -T | grep -A 15 "rules.conf"

Segurança de configuração#

Arquivos de configuração do Nginx ou do Fail2Ban nunca devem ficar em diretórios públicos acessíveis pela web com permissão de escrita para usuários comuns, pois qualquer brecha na aplicação web poderia permitir injeção de diretivas maliciosas. Mantenha esses arquivos de configuração protegidos com permissões restritas ao usuário de administração do host.


Comparativo técnico de comportamento#

AspectoFail2BanNginx
Diretiva de inclusão/etc/fail2ban/jail.d/*.conf ou [INCLUDES] / before = rules.confinclude ...;
Motor de parsingconfigparser do Python (dinâmico)Lexer em C (estático no boot/reload)
Comportamento em falhaCrash fatal (status=255/EXCEPTION)Falha no teste (nginx -t), mantendo o processo anterior ativo
Origem dos logsArquivos de texto ou Systemd JournalFormato nativo via access_log / error_log

Perguntas Frequentes (FAQ de Troubleshooting)#

Por que o Fail2ban encerra imediatamente com status 255 no systemd?#

O fail2ban-server é construído em Python. Quando uma jail está configurada para monitorar um caminho de log inexistente (como /var/log/auth.log) sem um backend tolerante, o interpretador lança a exceção crítica Failed during configuration: Have not found any log file for sshd jail. Como a falha ocorre no bootstrap do daemon, o systemd registra a saída como code=exited, status=255/EXCEPTION.

Vale a pena instalar o rsyslog apenas para corrigir o Fail2ban?#

Não. Instalar o rsyslog reintroduz overhead de I/O em disco desnecessário e duplica logs já gravados pelo systemd-journald. O caminho mais limpo, performático e moderno é adotar backend = systemd, consumindo os eventos de autenticação diretamente do Journal.

Como validar se o Fail2ban está bloqueando tentativas de intrusão no SSH?#

Após reiniciar o serviço com o backend do systemd, execute fail2ban-client status sshd. O comando exibirá a contagem de falhas recentes, o filtro em monitoramento e a lista de endereços IP que estão em quarentena no firewall.


Conclusão#

Neste artigo compartilhei um caso real em que a transição de logging — do rsyslog ao journal — quebrou o boot do Fail2Ban, e como backend = systemd resolveu sem reintroduzir daemons legados. A mesma disciplina de modularização, com includes bem posicionados e permissões restritas, vale para o Nginx.

Este artigo foi útil?

Deixe uma reação rápida para apoiar o conteúdo:

CC BY-NC

Este post está licenciado sob CC BY-NC.

Comentários

Participe da discussão abaixo.

0 comentários