Parte da nossa série Performance & Scalability
Leia o guia completoConfiguração de produção Nginx: SSL, cache e segurança
Nginx é o servidor web de produção que lida com praticamente todas as implantações web de alto tráfego. Quando bem configurado, ele fornece terminação SSL, serviço eficiente de arquivos estáticos, proxy WebSocket, limitação de taxa e cabeçalhos de segurança – tudo antes que uma única solicitação chegue ao seu aplicativo Node.js. Quando mal configurado, torna-se um gargalo, um problema de segurança ou a causa de misteriosos loops de redirecionamento da Cloudflare.
Este guia aborda uma configuração Nginx de nível de produção para uma implantação Node.js de vários aplicativos: frontend Next.js, API NestJS e documentos Docusaurus - todos em execução no mesmo servidor por trás do Cloudflare.
Principais conclusões
- Nunca divida www e não www em blocos de servidores separados atrás do Cloudflare — causa loops de redirecionamento
- Use um único arquivo de configuração Nginx em
/etc/nginx/conf.d/- não crie links simbólicos também emsites-enabled/X-XSS-Protectionestá obsoleto — use CSP;X-Frame-Options: DENYainda é válidoproxy_passdeve incluir a barra final ao usar um prefixo de caminho- Sempre vale a pena ativar a compactação Gzip para tipos de texto/* MIME
- A limitação de taxa requer
limit_req_zonedefinido no nívelhttp{}, não no nívelserver{}- Vamos criptografar a renovação automática de certificados com Certbot; adicione um cron job para recarregar o Nginx após a renovação
- O proxy WebSocket requer cabeçalhos específicos:
UpgradeeConnection
Estrutura de diretório
Mantenha a configuração do Nginx organizada:
/etc/nginx/
nginx.conf — Main config (rarely touch this)
conf.d/
ecosire-production.conf — All your server blocks in ONE file
snippets/
ssl-params.snippet — SSL hardening (included by server blocks)
proxy-params.snippet — Common proxy headers
security-headers.snippet — Security headers
Crítico: Coloque toda a sua configuração em conf.d/ecosire-production.conf. NÃO adicione-o também a sites-enabled/ — isso faz com que o Nginx processe a configuração duas vezes, levando a erros limit_req_zone duplicados e comportamento inesperado.
Zonas de limitação de taxa
Defina zonas de limitação de taxa no nível http{} em sua configuração. Eles não podem ser definidos dentro de blocos server{}:
# /etc/nginx/conf.d/ecosire-production.conf
# Must be at http{} level — these are in the main conf or conf.d root
limit_req_zone $binary_remote_addr zone=api_general:10m rate=60r/m;
limit_req_zone $binary_remote_addr zone=api_auth:10m rate=10r/m;
limit_req_zone $binary_remote_addr zone=api_public:10m rate=30r/m;
limit_req_zone $binary_remote_addr zone=static_files:10m rate=200r/m;
Bloco principal do servidor de aplicativos
# Main web application — Next.js on port 3000
server {
listen 80;
listen [::]:80;
server_name ecosire.com www.ecosire.com;
# Cloudflare handles SSL termination — Nginx only sees HTTP
# (If direct SSL, add listen 443 ssl and certificate paths)
# Security headers
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# CSP — adjust based on your needs
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://js.stripe.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; frame-src https://js.stripe.com; connect-src 'self' https://api.ecosire.com;" always;
# Remove server version from responses
server_tokens off;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
image/svg+xml
font/woff2;
gzip_min_length 1024;
# ─── Static Files: Next.js build output ─────────────────────────
location /_next/static/ {
proxy_pass http://127.0.0.1:3000;
add_header Cache-Control "public, max-age=31536000, immutable";
# Files include content hash in filename — safe to cache forever
}
# ─── Public static assets ────────────────────────────────────────
location /assets/ {
proxy_pass http://127.0.0.1:3000;
add_header Cache-Control "public, max-age=86400"; # 1 day
}
# ─── Well-known files (no locale prefix) ─────────────────────────
location /.well-known/ {
proxy_pass http://127.0.0.1:3000;
add_header Cache-Control "public, max-age=86400";
}
# ─── App routes (rate limited) ───────────────────────────────────
location / {
limit_req zone=api_general burst=20 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
proxy_cache_bypass $http_upgrade;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
Bloco de servidor API
# NestJS API — port 3001
server {
listen 80;
listen [::]:80;
server_name api.ecosire.com;
server_tokens off;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# CORS — handled by NestJS, but Nginx can add preflight response
# for performance (avoids reaching Node.js for OPTIONS)
location / {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin "https://ecosire.com";
add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
add_header Access-Control-Allow-Credentials "true";
add_header Access-Control-Max-Age 1728000;
add_header Content-Length 0;
return 204;
}
limit_req zone=api_general burst=30 nodelay;
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
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;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Stricter rate limits for auth endpoints
location ~ ^/api/auth/(login|exchange|callback) {
limit_req zone=api_auth burst=5 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:3001;
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 — no rate limiting
location /api/health {
proxy_pass http://127.0.0.1:3001;
proxy_set_header Host $host;
access_log off; # Don't log health check spam
}
# Stripe webhook — needs raw body
location /api/billing/webhook {
proxy_pass http://127.0.0.1:3001;
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;
# No rate limiting on webhooks — Stripe IPs are trusted
# NestJS validates the Stripe signature
}
}
Proxy WebSocket
Se seu aplicativo usa WebSockets (Socket.IO, gateway NestJS WebSocket), a configuração do proxy precisa de cabeçalhos específicos:
# WebSocket upgrade handling
location /ws/ {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade"; # Capital U required
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# WebSocket connections can be long-lived
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
Sem os cabeçalhos Upgrade e Connection, o handshake WebSocket do navegador falha com um erro 426 Upgrade Required ou 101 Switching Protocols.
SSL direto (sem Cloudflare)
Se não estiver usando Cloudflare, lide com a terminação SSL diretamente no Nginx:
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name ecosire.com;
ssl_certificate /etc/letsencrypt/live/ecosire.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ecosire.com/privkey.pem;
# SSL hardening
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# ... rest of server block
}
# HTTP to HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name ecosire.com www.ecosire.com;
return 301 https://ecosire.com$request_uri;
}
Configuração específica da Cloudflare
Atrás do Cloudflare, o Nginx vê apenas os IPs do Cloudflare. Para preservar IPs de clientes reais:
# Real IP from Cloudflare — add this in http{} or at top of server{}
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
real_ip_header CF-Connecting-IP;
Além disso: nunca divida www.ecosire.com e ecosire.com em blocos de servidor Nginx separados ao usar Cloudflare. Cloudflare lida com o redirecionamento www em sua borda. Se você adicionar um bloco de servidor www que redireciona para não www, e o Cloudflare também redirecionar www, você obterá um loop de redirecionamento (ERR_TOO_MANY_REDIRECTS).
Configuração de registro
# Custom log format with useful fields
log_format json_combined escape=json
'{'
'"time":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"cf_ip":"$http_cf_connecting_ip",'
'"method":"$request_method",'
'"uri":"$request_uri",'
'"status":$status,'
'"body_bytes":$body_bytes_sent,'
'"response_time":$request_time,'
'"referrer":"$http_referer",'
'"user_agent":"$http_user_agent"'
'}';
access_log /var/log/nginx/ecosire-access.log json_combined;
error_log /var/log/nginx/ecosire-error.log warn;
Testando sua configuração
# Test syntax before applying
nginx -t
# Reload without downtime
nginx -s reload
# Check which config file is active
nginx -T | grep "configuration file"
# Test a specific server block
curl -I https://ecosire.com
curl -I https://api.ecosire.com/api/health
# Check security headers
curl -I https://ecosire.com | grep -E "X-Frame|X-Content|Referrer|Content-Security"
Perguntas frequentes
Devo usar Nginx ou Caddy para um novo projeto?
Caddy é significativamente mais simples de configurar – ele lida com o Let's Encrypt SSL automaticamente e tem padrões sensatos prontos para uso. O Nginx é mais poderoso e possui um ecossistema maior de módulos e documentação. Para a maioria dos novos projetos, Caddy é o melhor ponto de partida; mude para Nginx se precisar de controle refinado sobre SSL, roteamento upstream complexo ou módulos específicos do Nginx. Para servidores Linux existentes onde o Nginx já está instalado, opte pelo Nginx.
Como evito o erro limit_req_zone duplicado?
A diretiva limit_req_zone deve aparecer no nível de contexto http{}, não dentro de blocos server{}. Em uma implantação Turborepo monorepo em que você inclui vários arquivos de configuração, certifique-se de que a diretiva apareça apenas uma vez em todos os arquivos incluídos. Se você estiver vendo o erro, verifique se você tem um link simbólico conf.d/app.conf e sites-enabled/ apontando para o mesmo arquivo.
Como configuro o Nginx para Next.js ISR (regeneração estática incremental)?
Next.js lida com ISR internamente - o Nginx só precisa fazer proxy de todas as solicitações para Next.js sem armazenar as respostas em cache. Não adicione cabeçalhos Cache-Control que interfiram nos cabeçalhos de cache ISR do Next.js. Para ativos estáticos em /_next/static/, adicione cabeçalhos de cache immutable, pois esses arquivos têm nomes com hash de conteúdo. Para todas as outras rotas, deixe Next.js definir os cabeçalhos de cache.
Por que minha pontuação SSL cai quando o Cloudflare está ativado?
Quando o Cloudflare está no modo proxy, o SSL Labs testa o SSL do Cloudflare, não o seu. Defina o modo SSL da Cloudflare como "Completo (estrito)" para garantir que a Cloudflare valide seu certificado de origem. Instale um certificado Cloudflare Origin em seu servidor — é gratuito e válido por 15 anos. Sua pontuação do SSL Labs se torna a pontuação da Cloudflare (geralmente A+), o que na verdade é uma melhoria em relação a uma configuração típica de SSL Nginx autoconfigurada.
Como lidar com vários aplicativos Node.js no mesmo servidor?
Execute cada aplicativo em uma porta diferente (Next.js em 3000, NestJS em 3001, Docusaurus em 3002, etc.) e adicione um bloco de servidor para cada subdomínio em sua configuração Nginx. Use PM2 para gerenciar todos os processos do Node.js. O Nginx roteia por subdomínio (ou prefixo de caminho) para a porta correta. Cada bloco de servidor pode ter sua própria configuração de limite de taxa, cache e cabeçalho de segurança.
Próximas etapas
Uma configuração de produção do Nginx é um documento vivo: ela evolui à medida que os requisitos do seu aplicativo mudam, os padrões de tráfego mudam e novas práticas recomendadas de segurança surgem. ECOSIRE executa Nginx em produção atendendo a vários aplicativos, lidando com terminação SSL, limitação de taxa e integração Cloudflare em todos os domínios.
Se você precisa de consultoria DevOps, configuração de infraestrutura de produção ou um projeto completo de arquitetura de implantação, explore nossos serviços para ver como podemos ajudar.
Escrito por
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
ECOSIRE
Expanda o seu negócio com ECOSIRE
Soluções empresariais em ERP, comércio eletrônico, IA, análise e automação.
Artigos Relacionados
Modelo de segurança OpenClaw, residência de dados, SOC 2 e ISO 27001
Arquitetura de segurança OpenClaw: isolamento de locatário, criptografia, gerenciamento de segredos, registros de auditoria, residência de dados, SOC 2, ISO 27001, GDPR, aptidão HIPAA.
Segurança em nível de linha do Power BI: padrões dinâmicos versus estáticos
Aprofundamento do Power BI RLS: funções estáticas versus dinâmicas, padrões USERPRINCIPALNAME, tabelas de segurança, hierarquias de gerenciadores, testes de RLS e RLS incorporado para SaaS.
Detecção de fraude por IA para comércio eletrônico: proteja a receita sem bloquear as vendas
Implemente a detecção de fraudes por IA que detecte mais de 95% das transações fraudulentas, mantendo as taxas de falsos positivos abaixo de 2%. Pontuação de ML, análise comportamental e guia de ROI.
Mais de Performance & Scalability
Odoo 19 HR: Matriz de Competências, Planos de Carreira, Ciclos de Desempenho
Atualização de RH Odoo 19: matriz de habilidades nativas, planejamento de carreira, ciclos de avaliação de desempenho, grade de 9 caixas, planejamento de sucessão, integração HRIS.
Benchmarks de desempenho do Odoo 19: números de ajuste do PostgreSQL 17
Benchmarks de desempenho do Odoo 19 no mundo real: velocidade do cliente web, taxa de transferência de ORM, configurações de ajuste PG17, pool de conexões, contagens de trabalhadores, limites de escala.
Otimização de custos do OpenClaw e eficiência de token em escala
Otimização de custos de token OpenClaw: cache de prompt, roteamento de modelo, cache de resposta, APIs em lote e proteções de custo por locatário para agentes de produção.
Atualização incremental do Power BI para tabelas com mais de 10 milhões de linhas
Manual de atualização incremental do Power BI para tabelas com mais de 10 milhões de linhas: design de partição, RangeStart/RangeEnd, políticas de atualização, dobramento de consultas e híbridos DirectQuery.
Depuração e monitoramento de webhook: o guia completo para solução de problemas
Domine a depuração de webhook com este guia completo que cobre padrões de falha, ferramentas de depuração, estratégias de repetição, painéis de monitoramento e práticas recomendadas de segurança.
Teste de carga k6: teste de resistência de suas APIs antes do lançamento
Domine o teste de carga k6 para APIs Node.js. Abrange aumentos de usuários virtuais, limites, cenários, HTTP/2, testes WebSocket, painéis Grafana e padrões de integração de CI.