Web Server

Nginx

Nginx é o servidor web orientado a eventos que fica à frente de quase toda aplicação Node, Python e Go em produção. Ele termina o TLS, serve arquivos estáticos, balanceia a carga e protege seu processo da internet.

intermediate15 min readUpdated 16 de set. de 2026
sites-available/app
nginx
# /etc/nginx/sites-available/app
server {
  listen 443 ssl;
  http2 on;
  server_name app.example.com;

  ssl_certificate     /etc/letsencrypt/live/app.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;

  location / {
    proxy_pass http://127.0.0.1:3000;
    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;
  }
}
Lançado
2004
Modelo
Event-driven, async
Papéis principais
Web server, reverse proxy, load balancer
Linguagem de config
Blocos declarativos
TLS
Terminado no Nginx
Upstreams típicos
Node, Python, Go, PHP

Por que importa

O que o Nginx tira da responsabilidade da sua aplicação

Um único ponto de entrada para tudo

Um único endereço público serve de frente para vários serviços. Roteie por hostname ou caminho para diferentes apps e mova-as sem alterar o DNS ou o código do cliente.

TLS e segurança na borda

O Nginx termina o HTTPS, redireciona HTTP simples, adiciona headers de segurança e aplica rate limits em tráfego abusivo antes mesmo de chegar ao seu processo.

Entrega rápida de estáticos e caching

Arquivos estáticos e respostas em cache são servidos do disco com sendfile e cache de kernel, o que é muito mais eficiente do que pedir para o Node fazer isso.

O panorama completo

As três funções do Nginx

Ele aceita conexões da internet, decide o que fazer com cada requisição e fala TLS para que sua app não precise fazer isso.

O listener

Aceitar

O Nginx vincula as portas, realiza o handshake TLS e lê a requisição. Sua app nunca vê o socket bruto.

O roteador

Corresponder

O server_name seleciona o host virtual, então os blocos location correspondem ao caminho e decidem se devem servir, fazer proxy, cachear ou rejeitar.

O upstream

Encaminhar

O proxy_pass entrega a requisição para sua aplicação, adiciona headers de encaminhamento e transmite a resposta de volta para o cliente.

Nginx em resumo

As diretivas que você mais usará

server blocks

Um por site ou hostname, selecionado por server_name e porta.

location blocks

Correspondem a um prefixo de caminho ou regex e escolhem como manipulá-lo.

proxy_pass

Encaminha uma requisição para uma app upstream ou outro servidor.

TLS

Certificados, protocolos e configurações de cipher ficam no server block.

upstream

Um pool de backends com um método de balanceamento e health checks.

limit_req & proxy_cache

Limita a taxa de abusadores e armazena respostas em cache para reduzir a carga na origem.

Fluxo

Uma requisição através do reverse proxy

Toda requisição segue o mesmo caminho, quer termine em um arquivo estático ou na sua aplicação.

  1. 1

    O cliente se conecta

    Um navegador abre uma conexão TCP na porta 443 no endereço público do servidor e inicia um handshake TLS.

  2. 2

    Nginx termina o TLS

    O Nginx apresenta o certificado e descriptografa a requisição, para que a aplicação upstream lide apenas com HTTP simples.

  3. 3

    O host virtual é escolhido

    O Nginx compara o header Host com o server_name para escolher o server block correto para aquele domínio.

  4. 4

    Um local é correspondido

    O caminho da requisição é comparado com os blocos location em ordem, e a correspondência mais específica decide o manipulador.

  5. 5

    A requisição é servida ou encaminhada

    O Nginx retorna um arquivo estático ou encaminha a requisição para o upstream definido por proxy_pass.

  6. 6

    Headers de encaminhamento são adicionados

    Host, X-Real-IP, X-Forwarded-For e X-Forwarded-Proto informam à app o cliente e o esquema reais.

  7. 7

    Caching e limites são aplicados

    O proxy_cache pode satisfazer a requisição a partir do disco, e o limit_req pode rejeitá-la, antes que qualquer coisa chegue ao upstream.

  8. 8

    A resposta retorna

    O Nginx transmite a resposta do upstream de volta para o cliente, opcionalmente comprimindo e adicionando headers no caminho.

O guia completo

Nginx: Tudo que voce precisa saber

O que o Nginx realmente é

O Nginx (pronuncia-se “engine-x”) é um servidor web construído em torno de uma arquitetura assíncrona e orientada a eventos. Em vez de utilizar uma thread ou processo por conexão, um pequeno número de processos worker gerencia milhares de conexões simultaneamente ao reagir a eventos. Esse design é o motivo pelo qual ele consegue ficar à frente de uma aplicação lenta sem travar, e por que se tornou a porta de entrada padrão para a web moderna.

Ele desempenha três papéis que são fáceis de confundir. Ele é um servidor web estático, entregando arquivos do disco com eficiência. É um reverse proxy, encaminhando requisições para outro servidor e retransmitindo a resposta. E é um load balancer, distribuindo as requisições entre um pool de backends. À frente de um app em Node.js, Python, Go ou PHP, você usará as três funções. O Nginx não faz parte da sua aplicação: ele é um processo separado, com sua própria configuração, ciclo de vida e logs.

Por que colocá-lo na frente do seu app

Você poderia vincular o Node diretamente à porta 80. Muitas pessoas fazem isso em tutoriais, e funciona até que pare de funcionar. Colocar o Nginx na frente garante um conjunto de funcionalidades que são tediosas ou perigosas de implementar dentro de uma aplicação.

TLS termination. O Nginx detém o certificado, realiza o handshake e descriptografa. Seu app fala HTTP simples no localhost e nunca precisa gerenciar a renovação de certificados. O Certbot pode até reescrever a configuração para você.

Arquivos estáticos, compressão e cache. O Nginx serve arquivos com sendfile e cache de kernel, comprime com gzip ou brotli, e pode repetir uma resposta armazenada sem sequer tocar no upstream.

Rate limiting e limites de requisição. Abusos são interrompidos na borda, antes que consumam um pool de conexões ou uma query no banco de dados.

Um único ponto de entrada. Um único endereço público e certificado podem servir a vários serviços, roteados por hostname ou path. Você pode mover um app para outra porta ou host sem alterar o DNS.

Zero-downtime deploys. Um upstream pode esvaziar um backend enquanto ele reinicia, e o reload da configuração é graceful. O Node exposto diretamente derruba todas as conexões em andamento ao reiniciar.

O modelo de configuração

A configuração do Nginx é uma árvore de contextos e diretivas. Uma diretiva é uma configuração que termina em ponto e vírgula; um contexto é um bloco delimitado por chaves que contém mais diretivas. As diretivas são herdadas para baixo, e o contexto mais específico prevalece.

# /etc/nginx/nginx.conf (main context)
user  www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
  worker_connections 1024;
}

http {
  include       /etc/nginx/mime.types;
  default_type  application/octet-stream;
  sendfile      on;
  keepalive_timeout 65;

  gzip on;
  gzip_types text/css application/javascript application/json;

  # site configs are pulled in here
  include /etc/nginx/conf.d/*.conf;
  include /etc/nginx/sites-enabled/*;
}

Os contextos com os quais você trabalhará são:

  • main — configurações globais, como user e worker_processes.
  • events — como as conexões são manipuladas.
  • http — tudo relacionado a HTTP: tipos MIME, logging, compressão e os includes que importam os arquivos do site.
  • server — um host virtual, selecionado por listen e server_name.
  • location — um caminho dentro de um server, onde as requisições são efetivamente processadas.

No Debian e Ubuntu, a convenção é manter um arquivo por site em /etc/nginx/sites-available/ e criar symlinks dos sites ativos em /etc/nginx/sites-enabled/. Isso oferece uma maneira fácil de desativar um site sem excluí-lo.

sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/app
sudo rm /etc/nginx/sites-enabled/app

Diretivas não são uma linguagem de script. Não existem loops ou variáveis no sentido usual — apenas map, if (usados com moderação) e includes. Se um problema parecer exigir fluxo de controle, a resposta geralmente é um map ou uma alteração na aplicação.

Seu primeiro server block

Um bloco server é um virtual host. Ele escuta em uma porta, responde por um ou mais nomes e contém blocos location.

server {
  listen 80;
  server_name app.example.com www.app.example.com;

  root /var/www/app/dist;
  index index.html;

  location / {
    try_files $uri $uri/ =404;
  }
}

O server_name é comparado com o header Host. O primeiro server block de uma porta é o default server e captura requisições cujo host não coincida com nenhum outro; por isso, vale a pena torná-lo um catch-all explícito que retorne 444 ou uma página de manutenção, em vez de expor um site indesejado.

A ordem de correspondência é importante e costuma confundir as pessoas. Blocos location são testados primeiro como correspondências exatas (=), depois a correspondência de prefixo mais longa e, por fim, regexes (~ e ~*). Um prefixo ^~ instrui o Nginx a parar e usar aquele prefixo sem verificar regexes. Quando o comportamento parece incorreto, geralmente é por causa dessa ordenação.

location = /favicon.ico { log_not_found off; access_log off; }
location ^~ /assets/    { expires 1y; }
location ~* \.(jpg|png|css|js)$ { expires 30d; }
location /              { try_files $uri /index.html; }

Fazendo proxy para um app Node.js

A diretiva principal é proxy_pass. Aponte-a para a sua aplicação e o Nginx se tornará um reverse proxy.

upstream app {
  server 127.0.0.1:3000;
  keepalive 32;
}

server {
  listen 80;
  server_name app.example.com;

  location / {
    proxy_pass http://app;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_read_timeout 30s;
    proxy_connect_timeout 5s;
  }
}

Definir um bloco upstream em vez de colocar o endereço inline não serve apenas para múltiplos servidores. É isso que permite configurar o keepalive, fazendo com que o Nginx reutilize as conexões com o backend em vez de abrir uma nova conexão TCP para cada requisição. O proxy_http_version 1.1 é necessário para o keepalive e para WebSockets.

Os timeouts merecem atenção. O proxy_connect_timeout limita quanto tempo o Nginx espera para estabelecer a conexão; o proxy_read_timeout limita quanto tempo ele espera pelo próximo byte do upstream. O timeout de leitura deve ser maior que a sua resposta legítima mais lenta, caso contrário, o Nginx retornará um 504 enquanto o app ainda estiver processando.

A regra da barra final (trailing-slash) é a armadilha clássica. proxy_pass http://app; encaminha o caminho completo sem alterações. proxy_pass http://app/; substitui o prefixo da location correspondente por /. Dentro de location /api/, o primeiro envia /api/users e o segundo envia /users. Escolha com critério e verifique o log do upstream.

Encaminhamento de headers e por que sua aplicação precisa disso

Por padrão, o upstream enxerga a requisição como vinda do Nginx: o endereço do cliente é 127.0.0.1, o scheme é http, e o header Host pode estar ausente. Isso quebra logs, redirecionamentos, cookies e rate limiting dentro da aplicação.

location / {
  proxy_pass http://app;
  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_set_header X-Forwarded-Host  $host;
  proxy_set_header X-Forwarded-Port  $server_port;
}

Cada header tem sua função:

  • Host preserva o domínio original, permitindo que a aplicação construa URLs absolutas e virtual hosts corretamente.
  • X-Real-IP é o endereço imediato do cliente.
  • X-Forwarded-For anexa a uma cadeia; $proxy_add_x_forwarded_for mantém as entradas existentes e adiciona o cliente atual. Use a primeira entrada como o cliente original, mas nunca confie nela cegamente.
  • X-Forwarded-Proto informa à aplicação se o usuário se conectou via HTTPS, o que corrige loops de redirecionamento e bugs de secure-cookie.
  • X-Forwarded-Host e X-Forwarded-Port são úteis quando o Nginx escuta em uma porta não padrão.

Seu framework deve ser configurado para confiar neste proxy. No Express, app.set("trust proxy", 1) faz com que req.ip e req.protocol leiam os valores encaminhados. Se pular essa etapa, cada requisição parecerá vir do localhost, o que quebrará silenciosamente a geolocalização e o rate limiting por IP.

Servindo arquivos estáticos e o fallback de SPA

O Nginx é excelente com arquivos estáticos, então deixe que ele cuide disso. Uma divisão comum é servir o frontend buildado a partir do disco e fazer o proxy apenas da API.

server {
  listen 80;
  server_name app.example.com;
  root /var/www/app/dist;

  location /assets/ {
    try_files $uri =404;
    expires 1y;
    add_header Cache-Control "public, immutable";
  }

  location /api/ {
    proxy_pass http://app;
    proxy_set_header Host $host;
  }

  location / {
    try_files $uri /index.html;
  }
}

Para um single-page app, try_files $uri /index.html é o fallback que faz o roteamento no client-side funcionar: se o caminho solicitado não for um arquivo, retorne index.html e deixe que o router resolva. Para uma API, o mesmo padrão com =404 é melhor, pois retornar HTML para um endpoint inexistente esconde bugs.

Assets com hashes de conteúdo em seus nomes podem ser cacheados para sempre — immutable e uma expiração de um ano são seguros, pois qualquer alteração gera um novo nome de arquivo. index.html nunca deve ser cacheado dessa forma, caso contrário, os usuários continuarão carregando uma versão antiga do app.

TLS com Let’s Encrypt e certbot

O Certbot obtém certificados gratuitos do Let’s Encrypt e pode configurar o Nginx automaticamente. Instale o plugin, execute-o uma vez por domínio e ele cuidará do restante.

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d app.example.com -d www.app.example.com
sudo certbot renew --dry-run

O Certbot escreve os caminhos dos certificados no seu server block e instala um timer de renovação. Os certificados duram 90 dias; a renovação é automática, mas só funciona se a verificação de renovação conseguir alcançar seu servidor na porta 80, portanto, não a bloqueie totalmente no firewall.

O bloco resultante fica assim, com um servidor HTTP que redireciona e um servidor HTTPS que finaliza a conexão.

server {
  listen 80;
  server_name app.example.com;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  http2 on;
  server_name app.example.com;

  ssl_certificate     /etc/letsencrypt/live/app.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;
  ssl_protocols       TLSv1.2 TLSv1.3;
  ssl_session_cache   shared:SSL:10m;
  ssl_session_timeout 1d;

  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
  add_header X-Content-Type-Options "nosniff" always;
  add_header Referrer-Policy "strict-origin-when-cross-origin" always;

  location / {
    proxy_pass http://app;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

TLSv1.2 e TLSv1.3 são os únicos protocolos que vale a pena habilitar hoje em dia. O HSTS informa aos navegadores que recusem HTTP simples por um ano, então habilite-o apenas quando tiver certeza de que o HTTPS funciona em todos os lugares — é difícil de reverter.

HTTP/2 e HTTP/3

O HTTP/2 multiplexa várias requisições em uma única conexão e é habilitado por servidor. No Nginx moderno (1.25.1 e posteriores), a diretiva é http2 on;. Em versões mais antigas, trata-se de uma flag na linha listen: listen 443 ssl http2;.

server {
  listen 443 ssl;
  http2 on;
  # ...
}

O HTTP/3 roda sobre QUIC e UDP. Ele requer um build com o módulo QUIC, uma linha listen 443 quic reuseport; separada e um header Alt-Svc: h3=":443"; ma=86400 para anunciá-lo. Trate-o como uma otimização para adicionar assim que o HTTP/2 estiver estável, e não como um primeiro passo. Os navegadores negociam ambos via TLS automaticamente, portanto não há nada a alterar no seu app.

Métodos de balanceamento de carga

Um bloco upstream define um pool, e o método de balanceamento decide qual servidor recebe a próxima requisição. O padrão é o round-robin.

upstream app {
  least_conn;
  server 10.0.0.11:3000 weight=2 max_fails=3 fail_timeout=15s;
  server 10.0.0.12:3000;
  server 10.0.0.13:3000 backup;
  keepalive 64;
}
  • Round-robin (padrão) alterna entre os servidores. Simples e eficiente quando as requisições têm custos semelhantes.
  • least_conn envia para o servidor com o menor número de conexões ativas. Melhor quando a duração das requisições varia muito, o que é comum em APIs.
  • ip_hash vincula um cliente a um único servidor através do hash do endereço. Útil para sessões em memória, porém com o custo de uma carga desigual e a perda da persistência quando um servidor falha.
  • weight direciona o tráfego preferencialmente para uma máquina mais potente ou durante um canary.
  • backup marca um servidor para receber tráfego apenas quando os primários estiverem fora do ar.

max_fails e fail_timeout oferecem verificação de saúde passiva: após max_fails falhas dentro de fail_timeout, o Nginx marca o servidor como indisponível durante aquele intervalo. O proxy_next_upstream então decide quais falhas devem ser repetidas em outro backend.

proxy_next_upstream error timeout http_502 http_503 http_504;

Tentar novamente (retry) é poderoso, mas não é gratuito: só faz sentido para requisições idempotentes. Não repita cegamente um POST que possa já ter alterado o estado, a menos que o upstream seja idempotente por design.

Health checks e tratamento de falhas

O Nginx OSS possui verificações passivas; verificações ativas de saúde (health_check com match) exigem o Nginx Plus. Verificações passivas combinadas com um endpoint no nível da aplicação costumam ser suficientes para a maioria dos times: exponha /healthz que verifique as dependências necessárias — banco de dados, cache — e retorne rapidamente, então aponte a liveness probe da sua plataforma para ele. Use isso para controlar deploys, iniciando um novo backend, aguardando até que ele esteja saudável e, então, removendo o antigo do upstream.

Como os reloads de configuração são suaves (graceful), o padrão para zero-downtime é editar o upstream para apontar para a nova instância, nginx -t, fazer o reload e, em seguida, drenar e parar a instância antiga.

Cache com proxy_cache

proxy_cache armazena as respostas do upstream no disco e as serve sem precisar contatar o backend. Para endpoints com alta carga de leitura que mudam lentamente, este é o maior ganho individual disponível na edge.

proxy_cache_path /var/cache/nginx levels=1:2
                 keys_zone=app:10m max_size=1g inactive=60m;

server {
  listen 80;
  server_name app.example.com;

  location /api/public/ {
    proxy_pass http://app;
    proxy_cache app;
    proxy_cache_key "$scheme$request_method$host$request_uri";
    proxy_cache_valid 200 302 10s;
    proxy_cache_valid 404 1m;
    proxy_cache_bypass $http_authorization $cookie_session;
    proxy_no_cache $http_authorization;
    add_header X-Cache-Status $upstream_cache_status;
  }
}

proxy_cache_valid define por quanto tempo cada código de status é cacheado. proxy_cache_bypass ignora o cache para requisições que contenham um header de sessão ou autorização; proxy_no_cache evita o armazenamento de suas respostas, garantindo que os dados privados de um usuário nunca sejam servidos a outro. O header X-Cache-Status (HIT, MISS, BYPASS, EXPIRED) é a maneira mais rápida de provar que o cache está funcionando.

Dois alertas. Cacheie apenas respostas que sejam seguras para compartilhar — dados públicos e não personalizados — e certifique-se de que o upstream envie um header Cache-Control compatível com a sua configuração. Uma cache key que ignore uma variante (um header de idioma, um parâmetro de query) servirá alegremente o conteúdo errado.

Rate limiting com limit_req

O rate limiting protege endpoints de login, busca e APIs públicas contra abusos e floods acidentais. Ele é definido no contexto http e aplicado em uma location.

limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_req_status 429;

server {
  listen 80;
  server_name app.example.com;

  location /api/ {
    limit_req zone=api burst=20 nodelay;
    proxy_pass http://app;
  }

  location = /api/login {
    limit_req zone=login burst=5 nodelay;
    proxy_pass http://app;
  }
}

A chave da zona geralmente é $binary_remote_addr (o IP do cliente), e a taxa é definida em requisições por segundo ou por minuto. O burst permite picos curtos, e o nodelay processa o burst imediatamente em vez de espaçá-lo — que é o comportamento desejado para endpoints interativos. Sem o nodelay, as requisições excedentes são atrasadas, o que pode deixar a UI com a sensação de lentidão em vez de simplesmente retornar 429.

Atrás de outro proxy ou de uma CDN, o $binary_remote_addr pode ser o endereço do proxy, fazendo com que o limiter trate todos como um único cliente. Corrija isso configurando set_real_ip_from e real_ip_header para que o Nginx veja o cliente real. Além disso, retorne 429 em vez do padrão 503 para que os clientes possam distinguir o rate limiting de uma queda no serviço.

Upgrade de WebSocket

Uma conexão WebSocket começa como uma requisição HTTP com um header Upgrade e, em seguida, torna-se um stream bidirecional de longa duração. Para fazer o proxy dessa conexão, são necessários os headers de upgrade e um valor Connection que depende da requisição, por isso utiliza-se um map.

map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

server {
  listen 443 ssl;
  http2 on;
  server_name app.example.com;

  location /ws/ {
    proxy_pass http://app;
    proxy_http_version 1.1;
    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_set_header Host       $host;
    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;
  }
}

O timeout de leitura longa é fundamental: um WebSocket inativo com um timeout curto é fechado pelo Nginx, e o cliente percebe uma desconexão misteriosa. Note que o HTTP/2 não transporta WebSocket da mesma maneira; os navegadores abrem uma conexão HTTP/1.1 separada para o upgrade, a qual o Nginx gerencia automaticamente na mesma porta.

Executando Nginx no Docker

A imagem oficial do nginx é uma maneira conveniente de distribuir configurações e arquivos estáticos com seu app. A única regra é que o processo principal do container deve permanecer em primeiro plano, por isso o comando termina com daemon off;.

# Dockerfile
FROM nginx:1.27-alpine
COPY nginx.conf /etc/nginx/conf.d/app.conf
COPY dist/ /usr/share/nginx/html/
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]

No Compose, o serviço do app é acessível pelo nome do serviço, então o host upstream é simplesmente app. O Nginx inicia antes do app estar pronto, portanto, adicione um healthcheck e dependa dele, ou deixe o Nginx tentar novamente.

# docker-compose.yml
services:
  nginx:
    image: nginx:1.27-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/app.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      app:
        condition: service_healthy
  app:
    build: .
    expose:
      - "3000"
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:3000/healthz"]
      interval: 5s
      retries: 10

Note o uso de expose em vez de ports no app: ele deve ser acessível apenas dentro da rede do Compose, nunca diretamente do host. O upstream da configuração do nginx torna-se server app:3000;.

Testes, recarregamento e alterações de configuração com zero-downtime

Toda alteração de configuração deve seguir o mesmo ciclo: validar, recarregar, verificar. Um reload é gracioso; um restart não é.

sudo nginx -t                 # test the configuration
sudo nginx -T                 # test and dump the full effective config
sudo systemctl reload nginx   # graceful, no dropped connections
sudo systemctl status nginx
curl -I https://app.example.com

nginx -T é subutilizado e extremamente útil: ele imprime a configuração mesclada exatamente como o Nginx a enxerga, o que resolve discussões sobre herança e includes. Se o -t falhar, o erro indica o arquivo e a linha.

Recarregar mantém um shell aberto em uma segunda sessão, para que uma configuração incorreta não bloqueie seu acesso. Em um container, o equivalente é enviar SIGHUP para o processo master ou executar nginx -s reload. Nunca reinicie um Nginx de produção com tráfego para aplicar uma alteração de configuração quando um reload resolve.

Melhores práticas

  • Execute nginx -t antes de cada reload; nunca edite e reinicie cegamente.
  • Mantenha um arquivo por site e ative-o com um symlink para que as alterações sejam reversíveis.
  • Defina um bloco upstream com keepalive em vez de colocar o endereço do backend inline.
  • Sempre encaminhe Host, X-Real-IP, X-Forwarded-For e X-Forwarded-Proto, e configure trust proxy no app.
  • Sirva assets estáticos e bundles com hash a partir do disco com headers de cache longos e imutáveis.
  • Redirecione HTTP para HTTPS e ative o HSTS apenas após o HTTPS estar comprovadamente funcionando.
  • Faça cache apenas de respostas públicas e não personalizadas, e nunca crie a chave de um cache sem suas variantes.
  • Aplique rate limit em endpoints de login e públicos, e retorne 429 em vez de 503.
  • Use timeouts longos para locações de WebSocket e curtos para health checks.
  • Mantenha secrets e certificados fora das imagens; monte-os como read-only em tempo de execução.

Erros comuns

  • Pular o nginx -t e derrubar o site com um erro de sintaxe.
  • Esquecer o X-Forwarded-Proto e acabar debugando um loop infinito de redirecionamento HTTPS.
  • Não habilitar o trust proxy no app, fazendo com que cada requisição pareça ter vindo do localhost.
  • Confundir proxy_pass com e sem a barra final (trailing slash) e receber erros 404.
  • Configurar o proxy_read_timeout com um tempo menor do que uma resposta lenta legítima e retornar erros 504.
  • Cachear respostas personalizadas e servir os dados de um usuário para outro.
  • Fazer o proxy de WebSockets sem o map de upgrade, resultando na queda imediata das conexões.
  • Deixar o servidor padrão como o primeiro bloco de site e expor um app indesejado.
  • Habilitar HSTS antes que o HTTPS funcione em todos os lugares e bloquear o acesso dos usuários por um ano.
  • Expor o serviço do app com ports no Compose em vez de expose.

Próximos passos

O Nginx é a porta de entrada, e o guia de HTTP / HTTPS explica o protocolo que ele encerra e encaminha. Para executá-lo ao lado do seu app de forma reprodutível, leia sobre Docker & Deployment, e para manter a saúde do host onde ele está rodando, revise a seção de Linux. Quando você estiver pronto para colocá-lo na internet pública com certificados, DNS e autoscaling, o guia de Cloud Deployment une todas essas peças.

Na pratica

As quatro configs que você mais escreverá

Comece com um proxy, adicione TLS, escale para um pool e, então, adicione camadas de caching e rate limiting.

sites-available/app
upstream app {
  server 127.0.0.1:3000;
  keepalive 32;
}

server {
  listen 80;
  server_name app.example.com;

  location / {
    proxy_pass http://app;
    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_read_timeout 30s;
  }
}

Reverse proxy vs expondo a app diretamente

Rodar Node na porta 80 significa abrir mão de TLS, cache estático, rate limiting e da capacidade de fazer deploy sem downtime. O Nginx custa um processo e entrega tudo isso.

Preferir
server {
  listen 443 ssl;
  server_name app.example.com;

  location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
  }
}
Evitar
# Node listening on :80 directly
# - no TLS termination
# - no static file cache
# - no rate limiting
# - restart drops connections
# - one process owns the port

ip_hash vs round-robin

Round-robin distribui a carga uniformemente. ip_hash fixa um cliente a um único backend, o que é útil para sticky sessions, mas cria carga desigual e perde essa fixação quando um servidor cai.

Carga uniforme
upstream app {
  least_conn;
  server 10.0.0.11:3000;
  server 10.0.0.12:3000;
}
# Stateless apps and shared
# session stores scale cleanly.
Sticky sessions
upstream app {
  ip_hash;
  server 10.0.0.11:3000;
  server 10.0.0.12:3000;
}
# Pins clients, but a restart
# reshuffles their sessions.

Trade-offs

O Nginx vale o processo extra?

O Nginx adiciona uma linguagem de configuração e um segundo item para fazer deploy. Para qualquer serviço público, os recursos de borda compensam esse custo rapidamente.

Strengths

  • Segurança na borda

    TLS, headers de segurança, limites de tamanho de requisição e rate limiting são aplicados antes que a requisição chegue ao código da aplicação, expondo menos os bugs.

  • Performance gratuita

    Arquivos estáticos, gzip e respostas em cache são servidos por um servidor C orientado a eventos, liberando a thread única do Node para o trabalho real.

  • Deploys sem downtime

    Recarregar o Nginx é suave (graceful), e um upstream pode esvaziar um backend enquanto ele reinicia, para que os usuários nunca vejam uma conexão recusada.

Trade-offs

  • Mais uma coisa para aprender e operar

    Sintaxe de config, regras de ordenação e semântica de reload são áreas consideráveis. Um erro de digitação pode derrubar um site se você pular o nginx -t.

  • A terminação TLS move a fronteira

    O tráfego entre o Nginx e o upstream é HTTP simples. Em um host ou rede compartilhada, criptografe ou isole esse salto também.

  • Pode esconder problemas da aplicação

    Caching e buffering mascaram origens lentas, e headers de encaminhamento são fáceis de esquecer, o que leva a IPs de clientes errados e redirecionamentos quebrados.

Perguntas frequentes

Perguntas frequentes

Keep learning

Related topics from the roadmap.

$ comecar a aprender

Pronto para aprender Nginx / Reverse Proxy?

Nosso tutorial interativo te guia por Nginx / Reverse Proxy passo a passo — com quizzes e codigo real que voce pode executar no navegador.