Nginx é o servidor web e proxy reverso mais usado no mundo — mais de 40% dos sites usam Nginx na frente da aplicação. Neste módulo você configura o Nginx como proxy reverso para uma API com múltiplas réplicas, adiciona rate limiting para proteger contra abuse, configura failover automático com proxy_next_upstream e aplica headers de segurança essenciais. A configuração de SSL é coberta no próximo módulo — aqui tratamos a base HTTP primeiro.
Por que Nginx em frente à API?
Estrutura de diretórios do Nginx
# Estrutura recomendada no repositório do projeto
nginx/
├── nginx.conf # configuração principal (worker_processes, events, http global)
└── sites/
├── api.conf # configuração do virtualhost da API
└── frontend.conf # (se servir frontend estático pelo Nginx)
# No docker-compose.prod.yml, monta assim:
# volumes:
# - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
# - ./nginx/sites:/etc/nginx/conf.d:ronginx.conf: configuração principal
# nginx/nginx.conf
user nginx;
worker_processes auto; # 1 worker por CPU core automaticamente
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024; # conexões simultâneas por worker
use epoll; # melhor performance no Linux
multi_accept on; # aceita múltiplas conexões por vez
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Formato de log com informações úteis
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct=$upstream_connect_time '
'uht=$upstream_header_time urt=$upstream_response_time';
access_log /var/log/nginx/access.log main;
# Performance
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# Ocultar versão do Nginx nos headers de resposta
server_tokens off;
# Compressão gzip para respostas de texto
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
gzip_min_length 1000;
gzip_vary on;
# ─── Rate limiting zones (definidas aqui, usadas nos sites) ────
# Limite por IP para a API: 10 req/s com burst de 20
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
# Limite mais rígido para endpoints de autenticação: 5 req/min
limit_req_zone $binary_remote_addr zone=auth:10m rate=5r/m;
# ─── Incluir configurações de sites ────────────────────────────
include /etc/nginx/conf.d/*.conf;
}sites/api.conf: proxy reverso com load balancing
# nginx/sites/api.conf
# ─── Upstream: grupo de backends da API ─────────────────────────
# Os nomes "api" referencia o serviço Docker Compose pelo nome
# Se tiver 2 réplicas (api-1 e api-2), use IPs ou nomes com porta
upstream api_backends {
# Round-robin por padrão entre os backends listados
server api:3000; # nome do serviço Docker, porta interna
# Com múltiplas réplicas explícitas (se não usar deploy.replicas):
# server api-1:3000;
# server api-2:3000;
# Configurações de health check e timeout do upstream
keepalive 32; # mantém 32 conexões HTTP keepalive com o backend
}
# ─── Servidor HTTP: redireciona para HTTPS ──────────────────────
server {
listen 80;
server_name api.seudominio.com;
# Desafio do Let's Encrypt (necessário para renovação de certificado)
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# Todo o resto redireciona para HTTPS
location / {
return 301 https://$host$request_uri;
}
}
# ─── Servidor HTTPS ─────────────────────────────────────────────
server {
listen 443 ssl http2;
server_name api.seudominio.com;
# Certificados SSL (gerados pelo Certbot — próximo módulo)
ssl_certificate /etc/letsencrypt/live/api.seudominio.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.seudominio.com/privkey.pem;
# Configuração SSL moderna (TLS 1.2 e 1.3 apenas)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# ─── Headers de segurança ───────────────────────────────────
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# ─── Rate limiting na API ───────────────────────────────────
limit_req zone=api burst=20 nodelay;
limit_req_status 429;
# ─── Proxy para a API ───────────────────────────────────────
location / {
proxy_pass http://api_backends;
# Headers necessários para a API conhecer o cliente real
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeouts razoáveis
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# Failover: se o backend retornar erro, tenta o próximo
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 2;
# HTTP/1.1 necessário para keepalive com o upstream
proxy_http_version 1.1;
proxy_set_header Connection "";
}
# Rate limiting mais rígido em endpoints de auth
location /api/v1/auth {
limit_req zone=auth burst=5 nodelay;
proxy_pass http://api_backends;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Health check público (sem rate limiting)
location /health {
proxy_pass http://api_backends;
access_log off; # não polui o log com health checks
}
}Rate limiting: entendendo burst e nodelay
Rate limiting no Nginx funciona com um algoritmo de leaky bucket. Entender burst e nodelay é crucial para não bloquear usuários legítimos:
# Exemplo prático de quando cada configuração é adequada:
# API pública — permite picos curtos (load de página com múltiplos requests)
limit_req zone=api burst=20 nodelay;
# Login/autenticação — mais restritivo, sem burst generoso
limit_req zone=auth burst=5;
# Endpoint de upload — processamento mais lento, timeout maior
location /api/upload {
limit_req zone=api burst=5;
client_max_body_size 50M;
proxy_read_timeout 300s;
proxy_pass http://api_backends;
}Headers de segurança: o que cada um faz
Testando a configuração
# Testar configuração sem reiniciar o Nginx (nunca reinicie sem testar)
docker compose exec nginx nginx -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
# Recarregar configuração sem downtime (graceful reload)
docker compose exec nginx nginx -s reload
# Testar headers de segurança com curl
curl -I https://api.seudominio.com
# HTTP/2 200
# strict-transport-security: max-age=31536000; includeSubDomains
# x-frame-options: DENY
# x-content-type-options: nosniff
# Testar rate limiting (vai retornar 429 após o burst)
for i in {1..30}; do
curl -s -o /dev/null -w "%{http_code}
" https://api.seudominio.com/api/test
done
# 200 200 200 ... 429 429 429
# Ver logs do Nginx em tempo real
docker compose logs -f nginx
# Ver acessos específicos (ajuda a diagnosticar problemas)
docker compose exec nginx tail -f /var/log/nginx/access.logPerguntas frequentes
❓ Meu backend usa WebSockets. O que preciso adicionar?
❓ Como servir arquivos estáticos do frontend pelo Nginx?
❓ O que é o header X-Real-IP e por que preciso dele?
Resumo. O Nginx está configurado como proxy reverso com upstream para múltiplas réplicas, rate limiting por zona (geral e de auth), failover automático, headers de segurança e redirecionamento HTTP→HTTPS. O próximo módulo adiciona o certificado SSL via Let's Encrypt para que o HTTPS funcione de verdade.