O que é reverse proxy (e por que usar)
Quando uma aplicação (Node.js, Python, Java etc.) roda em uma porta interna (por exemplo, 127.0.0.1:3000), você pode colocar o Nginx na frente dela para receber as requisições HTTP/HTTPS do cliente e encaminhar para a aplicação. Nesse papel, o Nginx atua como reverse proxy: o cliente conversa com o Nginx, e o Nginx conversa com o serviço interno.
Na prática, isso permite: padronizar a porta pública (80/443), centralizar TLS (HTTPS), aplicar limites e timeouts, registrar logs consistentes, e até rotear múltiplas aplicações por domínio/caminho sem expor portas internas.
Encaminhando requisições com proxy_pass
A diretiva central do reverse proxy no Nginx é proxy_pass. Ela define o upstream (destino) para onde o Nginx vai encaminhar a requisição.
Exemplo mínimo: proxy para um app em localhost
server { listen 80; server_name app.exemplo.local; location / { proxy_pass http://127.0.0.1:3000; }}Esse exemplo já encaminha as requisições para a aplicação, mas ainda faltam headers importantes e ajustes comuns (timeouts, buffering, WebSocket etc.).
proxy_pass com e sem barra final: diferença prática
A presença (ou ausência) da barra final em proxy_pass muda como o Nginx monta a URI repassada ao upstream. Isso é uma fonte comum de bugs, principalmente quando você publica uma aplicação em um subcaminho (ex.: /api/).
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
Caso A: proxy_pass sem barra final
Quando você usa proxy_pass http://127.0.0.1:3000 (sem a barra final), o Nginx tende a repassar a URI original como está.
location /api/ { proxy_pass http://127.0.0.1:3000;}Requisição do cliente: GET /api/users
Upstream recebe: GET /api/users
Isso é útil quando sua aplicação já espera o prefixo /api nas rotas.
Caso B: proxy_pass com barra final
Quando você usa proxy_pass http://127.0.0.1:3000/ (com barra final), o Nginx substitui o prefixo que casou no location pelo caminho do proxy_pass. Na prática, isso costuma remover o prefixo do location ao encaminhar.
location /api/ { proxy_pass http://127.0.0.1:3000/;}Requisição do cliente: GET /api/users
Upstream recebe: GET /users
Isso é útil quando você quer expor /api publicamente, mas sua aplicação interna foi construída para servir em / (sem o prefixo).
Regra mental rápida
- Sem barra final em
proxy_pass: normalmente preserva a URI como o cliente enviou. - Com barra final em
proxy_pass: normalmente reescreve/remapeia o caminho, removendo o prefixo dolocation(quando olocationé por prefixo, como/api/).
Se você notar 404 no upstream ao publicar em subcaminho, verifique primeiro essa diferença.
Headers essenciais ao fazer proxy
Ao atuar como reverse proxy, o Nginx vira o “cliente” do seu backend. Se você não repassar alguns headers, a aplicação pode perder informações importantes: host original, IP real do usuário, e se a conexão externa era HTTP ou HTTPS.
Conjunto recomendado de headers
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;}Host: preserva o host solicitado pelo cliente (útil para apps multi-tenant, geração de links, validações de domínio).X-Real-IP: envia o IP do cliente visto pelo Nginx.X-Forwarded-For: cadeia de IPs (cliente + proxies intermediários). Use$proxy_add_x_forwarded_forpara anexar sem sobrescrever.X-Forwarded-Proto: indica se o cliente acessou viahttpouhttps. Fundamental quando o TLS termina no Nginx e o backend recebe HTTP interno.
Observação: frameworks costumam ter configuração para “confiar” nesses headers (por exemplo, para registrar IP real ou montar URLs corretas). Se o app não estiver configurado para confiar no proxy, ele pode ignorar esses valores.
Timeouts básicos de proxy (evitando travamentos e 504)
Timeouts controlam quanto tempo o Nginx espera em diferentes fases da comunicação com o backend. Ajustes simples evitam conexões presas e ajudam a diagnosticar backends lentos.
Timeouts comuns
location / { proxy_pass http://127.0.0.1:3000; proxy_connect_timeout 5s; proxy_send_timeout 30s; proxy_read_timeout 30s;}proxy_connect_timeout: tempo máximo para estabelecer conexão TCP com o backend.proxy_send_timeout: tempo máximo para o Nginx enviar a requisição ao backend (útil se o backend estiver travando ao receber).proxy_read_timeout: tempo máximo esperando o backend responder (muito relevante para endpoints lentos).
Se você tem endpoints longos (relatórios, exportações), aumente proxy_read_timeout para esses caminhos específicos, em vez de aumentar globalmente.
Buffering de proxy: conceito e quando ajustar
O Nginx pode fazer buffering da resposta do backend: ele lê a resposta, armazena em buffers (memória e, dependendo do tamanho, disco), e então envia ao cliente. Isso pode melhorar desempenho e proteger o backend contra clientes lentos (slow clients), porque o backend termina de responder mais rápido para o Nginx.
Por outro lado, para respostas em streaming (SSE), alguns tipos de long-polling, ou quando você quer baixa latência “byte a byte”, o buffering pode atrapalhar, pois o Nginx pode segurar dados antes de repassar.
Diretivas conceituais mais usadas
location / { proxy_pass http://127.0.0.1:3000; proxy_buffering on; proxy_buffers 8 16k; proxy_buffer_size 16k;}Para casos de streaming, você pode desabilitar:
location /stream/ { proxy_pass http://127.0.0.1:3000; proxy_buffering off;}Use proxy_buffering off apenas onde fizer sentido, pois ele pode aumentar a pressão no backend quando muitos clientes são lentos.
Exemplo completo de reverse proxy (com headers e timeouts)
server { listen 80; server_name app.exemplo.local; 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; proxy_connect_timeout 5s; proxy_send_timeout 30s; proxy_read_timeout 30s; proxy_buffering on; }}Esse é um “padrão seguro” para começar. A partir daí, você ajusta por rota (por exemplo, /api/ com timeout maior, /stream/ sem buffering).
Laboratório: subir uma aplicação simples, publicar via Nginx e validar rotas
Objetivo
Você vai: (1) subir um app HTTP local na porta 3000, (2) configurar o Nginx como reverse proxy, (3) validar headers e rotas, e (4) testar o efeito da barra final no proxy_pass.
1) Criar uma aplicação simples (Node.js)
Crie uma pasta e um arquivo server.js:
const http = require('http');const server = http.createServer((req, res) => { if (req.url === '/health') { res.writeHead(200, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ ok: true })); } if (req.url.startsWith('/api/')) { res.writeHead(200, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ route: req.url, host: req.headers['host'], xRealIp: req.headers['x-real-ip'], xForwardedFor: req.headers['x-forwarded-for'], xForwardedProto: req.headers['x-forwarded-proto'] })); } res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Hello from backend on :3000\n');});server.listen(3000, '127.0.0.1', () => { console.log('Backend listening on http://127.0.0.1:3000');});Suba o backend:
node server.jsTeste direto (sem Nginx):
curl -i http://127.0.0.1:3000/healthcurl -i http://127.0.0.1:3000/api/test2) Criar a configuração do Nginx para publicar o app
Crie um arquivo de site (o caminho varia por distro, mas o conteúdo é o importante). Exemplo de conteúdo:
server { listen 80; server_name app.exemplo.local; 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; proxy_connect_timeout 5s; proxy_send_timeout 30s; proxy_read_timeout 30s; proxy_buffering on; }}Valide a sintaxe e recarregue o Nginx:
sudo nginx -tsudo nginx -s reloadSe você não tiver DNS para app.exemplo.local, você pode testar com curl enviando o Host:
curl -i -H 'Host: app.exemplo.local' http://127.0.0.1/healthcurl -i -H 'Host: app.exemplo.local' http://127.0.0.1/api/test3) Validar que os headers chegaram no backend
A rota /api/test devolve os headers recebidos. Verifique se aparecem host, x-real-ip, x-forwarded-for e x-forwarded-proto no JSON.
Para simular um IP anterior na cadeia (como se houvesse outro proxy antes do Nginx), envie um X-Forwarded-For manualmente e veja se o Nginx anexou:
curl -s -H 'Host: app.exemplo.local' -H 'X-Forwarded-For: 203.0.113.10' http://127.0.0.1/api/testO backend deve receber algo como 203.0.113.10, <ip_do_cliente>.
4) Testar na prática a diferença do proxy_pass com e sem barra final
Agora publique o backend em um subcaminho, por exemplo /backend/, e observe como a URL chega ao app.
Teste 1 (sem barra final):
server { listen 80; server_name app.exemplo.local; location /backend/ { 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; }}Recarregue e teste:
sudo nginx -t && sudo nginx -s reloadcurl -s -H 'Host: app.exemplo.local' http://127.0.0.1/backend/api/testVocê deve ver no JSON a rota como /backend/api/test (o prefixo foi preservado).
Teste 2 (com barra final):
server { listen 80; server_name app.exemplo.local; location /backend/ { 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; }}Recarregue e teste novamente:
sudo nginx -t && sudo nginx -s reloadcurl -s -H 'Host: app.exemplo.local' http://127.0.0.1/backend/api/testAgora a rota tende a chegar como /api/test (o prefixo /backend/ foi removido no encaminhamento). Esse é o comportamento desejado quando você quer “montar” o app interno em um caminho público diferente.
5) Ajustar timeouts por rota (exercício rápido)
Se você tivesse uma rota lenta, você poderia aumentar apenas nela:
location /api/relatorio/ { 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; proxy_read_timeout 120s;}O restante do site continua com timeouts menores, evitando conexões abertas por muito tempo sem necessidade.