Nginx é amplamente reconhecido como um dos servidores web mais performáticos e estáveis do mercado, mas sua verdadeira força reside na capacidade de atuar como uma barreira robusta contra ataques de negação de serviço (DoS) e Distributed Denial of Service (DDoS). Para profissionais de segurança linux e sysadmins, configurar corretamente os limites de conexão e o rate limiting não é apenas uma otimização de performance, mas uma medida crítica de hardening para manter a disponibilidade dos serviços sob pressão.
Este tutorial técnico detalha como implementar estratégias eficazes de proteção anti-DoS diretamente na configuração do Nginx. Vamos abordar desde a limitação básica de conexões simultâneas até o uso avançado de zonas de memória para controle granular de requisições, garantindo que seu servidor não colapse durante picos de tráfego malicioso ou legítimo.
Entendendo a Ameaça e a Estratégia de Defesa
Ataques DoS visam esgotar os recursos do servidor (CPU, memória ou largura de banda) para tornar o serviço indisponível. Ataques DDoS amplificam essa técnica utilizando múltiplas fontes. O Nginx, por ser orientado a eventos e assíncrono, lida melhor com milhares de conexões concorrentes do que servidores baseados em processo (como Apache no modo prefork). No entanto, sem configuração adequada, um ataque massivo pode saturar a stack de rede do kernel Linux ou sobrecarregar o Nginx até o ponto de não responder.
A estratégia de defesa divide-se em três pilares:
- Limitação de Conexões Globais: Impede que um único IP abra uma quantidade infinita de conexões TCP simultâneas.
- Rate Limiting (Limite de Taxa): Controla quantas requisições HTTP um cliente pode enviar em um intervalo de tempo específico.
- Proteção contra Bursts: Permite picos curtos de tráfego sem bloquear usuários legítimos que navegam rapidamente, enquanto filtra robôs agressivos.
Passo 1: Configuração Básica do Nginx e Limites Globais
Antes de aplicar regras complexas, é fundamental ajustar os limites globais no bloco http. Isso estabelece o teto máximo de conexões que o servidor aceitará antes de rejeitar novas tentativas.
- Acesse seu servidor Linux e edite o arquivo principal de configuração do Nginx. Em distribuições baseadas em Debian/Ubuntu, o caminho padrão é
/etc/nginx/nginx.conf. No CentOS/RHEL, pode estar em/etc/nginx/conf.d/default.confou incluído viainclude.
Localize o bloco http e adicione a diretiva limit_conn_zone. Esta diretiva define uma zona de memória compartilhada onde o Nginx armazena o estado das conexões. Sem isso, o rate limiting não funcionará.
http {
# Define uma zona chamada 'addr' que usa 10MB de memória RAM.
# $binary_remote_addr é a chave (IP do cliente), ocupando 4 bytes por entrada.
limit_conn_zone $binary_remote_addr zone=addr:10m;
# Define outra zona para limitar conexões globais por IP
limit_conn_zone $server_name zone=perserver:10m;
server {
listen 80;
server_name seu-dominio.com.br;
# Limita o número total de conexões simultâneas por endereço IP para 10.
# Isso protege contra scanners de portas ou scripts que abrem muitas conexões TCP.
limit_conn addr 10;
# Opcional: Limitar conexões totais por servidor virtual (nome do host)
# Útil se você tiver muitos sites no mesmo IP e quiser isolar recursos.
limit_conn perserver 100;
}
}
Nota Técnica: A diretiva limit_conn aplicada acima conta o número de conexões simultâneas, não requisições HTTP. Um único usuário com uma página pesada pode manter a conexão aberta por vários segundos, consumindo uma "vaga" desse limite. Isso é crucial para mitigar ataques que mantêm conexões abertas deliberadamente (Slowloris).
Passo 2: Implementando Rate Limiting (Controle de Taxa)
O rate limiting é a ferramenta mais poderosa contra bots e ataques de força bruta. Ele impede que um cliente faça mais do que X requisições por segundo. Para isso, precisamos definir uma zona de taxa no bloco http.
http {
# Cria uma zona chamada 'one' baseada no IP do cliente.
# rate=10r/s significa 10 requisições por segundo.
# A memória de 10MB suporta aproximadamente 160.000 endereços IP únicos.
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
server {
listen 80;
server_name seu-dominio.com.br;
# Aplica a restrição às requisições padrão
location / {
# Nega excessos com código 503 (Service Temporarily Unavailable)
limit_req zone=one burst=20 nodelay;
proxy_pass http://backend_app;
}
# Proteja endpoints sensíveis com limites mais rigorosos
location /login {
# Apenas 1 requisição por segundo para login, com pequeno burst
limit_req zone=one burst=5 nodelay;
}
# Permita acesso livre para recursos estáticos (imagens, CSS, JS)
# Se você limitar isso, pode quebrar a experiência do usuário legítimo.
location ~* \.(jpg|jpeg|png|gif|css|js)$ {
# Não aplica limitação de taxa aqui, ou use uma zona separada mais permissiva
expires 30d;
}
}
}
Aqui estão os parâmetros essenciais para entender:
rate: A taxa média permitida (ex:10r/s,30r/m). O Nginx usa um algoritmo de token bucket suavizado.burst: Permite que o servidor aceite picos temporários acima da taxa média. Se você definirrate=10r/seburst=20, o Nginx aceita os primeiros 10 requests imediatamente e pode "empilhar" até 20 extras no buffer antes de começar a negar.nodelay: Se usado comburst, as requisições dentro do limite de burst são processadas imediatamente. Sem esta flag, elas seriam atrasadas (delayed) para respeitar a taxa média, o que pode causar timeouts no cliente.
Passo 3: Personalizando Respostas de Erro
Por padrão, quando o limite é excedido, o Nginx retorna o código HTTP 503 Service Temporarily Unavailable. Embora seja o padrão RFC, alguns administradores preferem retornar 403 Forbidden ou até mesmo um HTML personalizado para confundir atacantes ou fornecer informações claras.
Para alterar o código de retorno globalmente, adicione a diretiva abaixo no bloco http:
http {
# Retorna 403 em vez de 503 quando o limite é excedido
limit_req_status 403;
limit_conn_status 403;
}
Se desejar uma página HTML customizada para o erro, você pode usar a diretiva error_page dentro do bloco server:
server {
error_page 503 /custom_503.html;
location = /custom_503.html {
root /usr/share/nginx/html;
internal; # Apenas acessível internamente pelo Nginx, não por usuários finais
}
}
Passo 4: Whitelisting (Lista de Permissões)
Nenhuma configuração de segurança deve bloquear inadvertidamente seus próprios serviços, bots de monitoramento ou parceiros de API. É vital implementar uma lógica de exceção.
http {
# Define um mapa para classificar IPs confiáveis como 0 (sem limite)
map $binary_remote_addr $limit {
default 1;
# Adicione seus IPs de monitoramento, VPN corporativa ou API keys aqui
203.0.113.5 0;
198.51.100.0/24 0;
}
server {
location / {
# Usa a variável $limit definida no mapa
# Se $limit for 0, a restrição é ignorada
limit_req zone=one burst=20 nodelay delay=$limit;
# Nota: O uso de variáveis na diretiva limit_req pode ter implicações de performance em grandes escalas.
# Em cenários críticos, considere usar blocos 'if' separados ou upstreams distintos para IPs confiáveis.
}
}
}
Atenção: O uso de variáveis dentro de diretivas como limit_req impede o Nginx de otimizar a zona de memória em tempo de compilação, podendo aumentar ligeiramente o uso de CPU. Para hardening extremo, é recomendado criar um bloco server separado para IPs confiáveis que não aplica limitações, ou usar módulos upstreams.
Passo 5: Testando e Aplicando a Configuração
Após editar o arquivo de configuração, nunca reinicie o Nginx sem testar a sintaxe primeiro. Um erro de digitação pode impedir o serviço de iniciar, deixando seu servidor offline.
- Teste a configuração:
sudo nginx -t
Se a saída indicar syntax is ok e test is successful, proceda com o reload para aplicar as mudanças sem downtime:
sudo systemctl reload nginx
Se houver erro, verifique o log em /var/log/nginx/error.log para identificar a linha problemática.
Passo 6: Monitoramento e Ajuste Fino
A configuração inicial é apenas um ponto de partida. Você deve monitorar como o sistema se comporta sob carga real ou simulada.
- Logs: Ative o log de rejeições para auditar ataques. Adicione ao bloco
http:log_format anti_dos '$remote_addr - $time_local "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" limit_req_status=$limit_req_status'; access_log /var/log/nginx/anti_dos.log anti_dos; - Teste de Carga: Use ferramentas como
wrk,ab(Apache Bench) ouheypara simular tráfego. Exemplo comwrk:
wrk -t12 -c400 -d30s http://seu-dominio.com.br/
Observe no log de erros quantos códigos 403 ou 503 foram gerados. Se muitos usuários legítimos estiverem sendo bloqueados, aumente o valor de burst ou diminua a rigidez da taxa rate. Se bots continuarem passando, reduza o burst.
Considerações Finais sobre Hardening
O Nginx é uma linha de defesa excelente na borda (edge), mas não substitui uma solução dedicada de proteção contra DDoS em camada de rede (L3/L4) para ataques volumétricos massivos. Para ataques acima da capacidade de banda do seu datacenter ou ISP, você precisará de serviços como Cloudflare, AWS Shield ou Proxmox Anti-DDoS.
No entanto, para a maioria dos cenários comuns — desde ataques de força bruta em login até bots que consomem largura de banda excessiva — as configurações de limites de conexão e rate limiting descritas aqui são suficientes para manter sua infraestrutura estável. Combine essas técnicas com um firewall robusto (como iptables, nftables ou fail2ban) para uma postura de segurança em camadas eficaz.
Lembre-se: a segurança é um processo contínuo. Reavalite suas regras de limitação periodicamente, especialmente após atualizações de versão do Nginx ou mudanças na arquitetura da sua aplicação.