Do scan de .env ao bloqueio no kernel: minha jornada com CloudPanel, Nginx e CrowdSec
Voltar para blog

Do scan de .env ao bloqueio no kernel: minha jornada com CloudPanel, Nginx e CrowdSec

10/09/2026 · 5 min · Cibersegurança

Se você mantém servidores web expostos à internet, com certeza já viu esse padrão: ao abrir os logs de acesso, há uma enxurrada de requisições procurando por segredos, variáveis de ambiente e arquivos de configuração.

Recentemente, passei por esse cenário em um servidor rodando CloudPanel (sobre Debian 12) com Nginx. O que começou como uma simples tentativa de bloquear varreduras maliciosas evoluiu para uma sessão de troubleshooting envolvendo conflitos de portas TCP, falta de módulos Lua no Nginx e decisões de arquitetura de rede no nível do kernel.

Abaixo, compartilho o passo a passo, os erros encontrados e a solução definitiva.

1. O problema inicial: scans insistentes de arquivos .env#

Ao analisar o arquivo de access log do Nginx, identifiquei um bot realizando varreduras automatizadas em busca de credenciais:

2026-04-04 17:20:31 192.0.2.1 - - [04/Apr/2026:17:20:31 -0300] "GET /.env.production.debug HTTP/2.0" 404 1827 "-" "Mozilla/5.0..."
2026-04-04 17:20:31 192.0.2.1 - - [04/Apr/2026:17:20:31 -0300] "GET /.env.production.local HTTP/2.0" 404 1827 "-" "Mozilla/5.0..."
2026-04-04 17:20:31 192.0.2.1 - - [04/Apr/2026:17:20:31 -0300] "GET /.env.staging HTTP/2.0" 404 1827 "-" "Mozilla/5.0..."
2026-04-04 17:20:32 192.0.2.1 - - [04/Apr/2026:17:20:32 -0300] "GET /@fs/.docker.env?import HTTP/2.0" 404 1827 "-" "Mozilla/5.0..."
2026-04-04 17:20:33 192.0.2.1 - - [04/Apr/2026:17:20:33 -0300] "GET /@fs/.env.development?import HTTP/2.0" 404 1827 "-" "Mozilla/5.0..."

O bot procurava arquivos .env, configurações do Docker e até caminhos como /@fs/ (tentativa de explorar o servidor de desenvolvimento do Vite exposto).

Mesmo retornando 404 (Not Found), esse tráfego consome I/O e processamento no Nginx ao disparar chamadas de sistema (stat(), open()) no sistema de arquivos.

2. A escolha da ferramenta de mitigação e inteligência coletiva#

Avaliei três opções principais de proteção:

Como a arquitetura funciona por baixo do capô#

O CrowdSec separa a camada de detecção da camada de remediação:

[ Logs dos Serviços ] (Nginx, Apache, WordPress, etc.)
               │
               ▼
   [ Parsers & Scenarios ]  ──>  [ Local API (LAPI) ]  <──>  [ CrowdSec Central Hub ]
   (Detecção Assíncrona)         (Gestão de Decisões)         (Reputação Colaborativa)
                                         │
                                         ▼
                           [ Bouncers (Remediação) ]
                                         │
                                         ▼
                               [ nftables / Netfilter ]
  1. Parsers e Cenários: Normalizam logs de aplicações de forma assíncrona sem prender threads do servidor web.
  2. Local API (LAPI): Centraliza alertas e gerencia as decisões de bloqueio localmente.
  3. Consenso Global: A rede comunitária compartilha sinais de IPs maliciosos confirmados mundialmente, criando uma barreira proativa antes mesmo do primeiro ataque local.
  4. Remediação via Bouncers: A aplicação da regra de bloqueio é delegada a bouncers dedicados.

Optei pelo CrowdSec. A ideia inicial era instalar o motor de segurança e usar o bouncer do Nginx (crowdsec-nginx-bouncer) via Lua. Foi aí que os desafios apareceram.

3. Primeiro obstáculo: conflito na porta 8080#

Após a instalação do CrowdSec no Debian, o serviço entrou em falha (status=1/FAILURE). O log do systemd entregou a causa:

journalctl -u crowdsec -n 50 --no-pager
FATAL local API server stopped with error: listening on 127.0.0.1:8080: listen tcp 127.0.0.1:8080: bind: address already in use

No CloudPanel, a porta 8080 já estava ocupada pelos serviços internos da stack (como o proxy reverso de cache Varnish ou daemons de suporte, o que pode ser inspecionado executando ss -tulpn | grep 8080).

A solução: mudando a LAPI para a porta 8090#

  1. Editei /etc/crowdsec/config.yaml:
   api:
     server:
       listen_addr: 127.0.0.1:8090
  1. Atualizei as credenciais do cliente local em /etc/crowdsec/local_api_credentials.yaml:
   url: http://127.0.0.1:8090
  1. Reiniciei o serviço:
   sudo systemctl restart crowdsec

O comando ss -tulpn | grep crowdsec confirmou a LAPI rodando com sucesso na porta 8090.

4. O gargalo do módulo lua no Nginx do CloudPanel#

Com o motor ativo, instalei o crowdsec-nginx-bouncer. No entanto, no painel web do CrowdSec Console (app.crowdsec.net), aparecia o alerta:

"Inactive Remediation Components detected. Affected Security Engines may be unprotected."

Ao listar os bouncers registrados localmente:

sudo cscli bouncers list

O tipo aparecia como curl e a versão como a do utilitário de terminal (7.88.1). O Nginx nunca havia completado uma consulta na LAPI.

Ao tentar testar a rota com curl -I http://localhost/.env, o servidor respondeu:

curl: (52) Empty reply from server

E o comando nginx -t acusou erro fatal:

nginx: [emerg] open() "/etc/nginx/modules-enabled/10-mod-http-lua.conf" failed (2: No such file or directory)

Uma busca por ngx_http_lua_module.so no filesystem não retornou nenhum binário. A compilação padrão do Nginx utilizada pelo CloudPanel no Debian Bookworm não inclui o módulo dinâmico do Lua, tornando inviável rodar o bouncer embutido no processo HTTP sem recompilar o servidor web.

5. Pivotando para a solução superior: bloqueio no kernel com nftables#

Em vez de insistir em módulos Lua incompatíveis, mudei a camada de defesa: passei a bloquear os atacantes na Camada de Rede (Kernel) via NFTables.

Essa abordagem traz vantagens claras:

  1. O CrowdSec monitora os logs do Nginx em disco de forma assíncrona.
  2. Ao detectar comportamento abusivo, adiciona o IP em um conjunto (set) do firewall.
  3. O pacote do atacante é descartado pelo Netfilter no kernel antes mesmo de consumir memória ou sockets no Nginx.

Passo 1: Limpeza do Nginx#

sudo apt-get remove --purge crowdsec-nginx-bouncer
sudo rm -f /etc/nginx/conf.d/crowdsec_nginx.conf

Passo 2: Instalação do firewall bouncer#

sudo apt-get install nftables crowdsec-firewall-bouncer-nftables
sudo systemctl enable nftables
sudo systemctl start nftables

Gerei a chave de API para o novo bouncer:

sudo cscli bouncers add cs-firewall-bouncer

Editei /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml:

mode: nftables
api_url: http://127.0.0.1:8090/
api_key: <MINHA_API_KEY_GERADA>
log_mode: file

Iniciei o serviço:

sudo systemctl restart crowdsec-firewall-bouncer

6. O erro de ordem no nginx.conf: load_module#

Ao restaurar o Nginx, o comando nginx -t retornou outro erro clássico de sintaxe:

nginx: [emerg] "load_module" directive is specified too late in /etc/nginx/nginx.conf:13

A diretiva para carregar módulos adicionais estava posicionada após o bloco events {}. No Nginx, qualquer load_module precisa estar no topo do contexto global (main), antes de qualquer bloco:

user root; # Padrão em templates do CloudPanel; em servidores Debian puros prefira user www-data;
worker_processes auto;
pid /run/nginx.pid;
worker_rlimit_nofile 8192;

# Posicionado no topo do contexto global:
load_module modules/ngx_http_geoip_module.so;

events {
    worker_connections 2000;
}

http {
    ...

Validei e recarreguei o Nginx:

sudo nginx -t
sudo systemctl restart nginx

7. Validação e resultados#

Ao checar a lista de bouncers ativos:

sudo cscli bouncers list

A saída confirmou a comunicação contínua:

───────────────────────────────────────────────────────────────────────────────────────────────────
 Name                            IP Address  Valid  Last API pull         Type                       
───────────────────────────────────────────────────────────────────────────────────────────────────
 cs-firewall-bouncer-1775341453  127.0.0.1   ✔️     2026-04-04T22:25:04Z  crowdsec-firewall-bouncer  
───────────────────────────────────────────────────────────────────────────────────────────────────

O Last API pull passou a registrar atividade na porta 8090, o alerta no painel web desapareceu e o arquivo /var/log/crowdsec.log passou a registrar o ban automático de IPs maliciosos por 4 horas diretamente no firewall.

Conclusão: principais lições e recomendações#

  1. Nem todo ambiente aceita bouncer de aplicação: Em servidores com Nginx customizado (como no CloudPanel), o bouncer via NFTables no kernel é muito mais estável e consome menos CPU.
  2. Evite colisões de porta padrão: A porta 8080 costuma colidir com proxies e painéis web. Mover a LAPI do CrowdSec para a porta 8090 garante uma inicialização limpa.
  3. Ordem estrita no Nginx: Módulos dinâmicos devem residir obrigatoriamente no topo do nginx.conf, antes dos blocos events e http.

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