Nginx reverse proxy e a anatomia de 502, 503 e 504
Objetivos desta aula
- Configurar reverse proxy com upstream
- Ajustar timeouts
- Diagnosticar cada 5xx pela evidência certa
O reverse proxy é a porta da aplicação: termina TLS, distribui carga, serve estáticos, aplica limites e esconde a topologia interna. A configuração mínima define um upstream, repassa cabeçalhos essenciais e ajusta timeouts coerentes com o comportamento da aplicação.
Os três 5xx contam histórias diferentes. 502 Bad Gateway: o proxy conseguiu tentar, mas o upstream recusou ou fechou a conexão — normalmente processo caído, porta errada ou reinício. 503 Service Unavailable: não há upstream disponível, ou o próprio proxy está limitando (rate limit, todos os backends marcados como falhos). 504 Gateway Timeout: o upstream aceitou mas demorou além do proxy_read_timeout — quase sempre consulta lenta ou dependência travada.
O procedimento é sempre o mesmo: ler o error.log do Nginx (a mensagem entre parênteses é ouro), testar o upstream direto com curl, verificar quem escuta a porta e só então mexer em configuração. Aumentar timeout sem entender a causa transforma erro rápido em lentidão prolongada.
1. O que um reverse proxy faz
O Nginx recebe a conexão do cliente, termina o TLS, aplica regras (limites, headers, cache, compressão) e repassa ao upstream — sua API Node em 127.0.0.1:3000. O cliente nunca fala direto com a aplicação.
2. Estrutura da configuração
http contém server (um site por server_name), que contém location (regras por caminho). Sempre valide com nginx -t antes de systemctl reload nginx; reload não derruba conexões, restart derruba.
3. 502, 503 e 504 pelo log
- 502 Bad Gateway: o upstream recusou, fechou a conexão ou devolveu lixo. Log: connect() failed (111) ou upstream prematurely closed.
- 503 Service Unavailable: não há upstream disponível ou há limite/manutenção.
- 504 Gateway Timeout: o upstream aceitou mas não respondeu dentro de
proxy_read_timeout.
4. Timeouts conscientes
Aumentar timeout esconde lentidão; diminuir demais corta operações legítimas. Meça o p99 da rota e defina o timeout um pouco acima, documentando o motivo.
5. Balanceamento de carga
Um bloco upstream com vários servidores distribui por round-robin; max_fails e fail_timeout tiram temporariamente do rodízio um backend doente.
6. Checagem final
Você deve conseguir ler o error.log e dizer em segundos se o problema é o upstream parado, lento ou inexistente.
Na prática
Nginx como reverse proxy do CloudShop
nginx
upstream cloudshop_api {
server 127.0.0.1:3000 max_fails=3 fail_timeout=10s;
keepalive 32;
}
server {
listen 443 ssl;
http2 on;
server_name api.cloudshop.dev;
ssl_certificate /etc/letsencrypt/live/api.cloudshop.dev/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.cloudshop.dev/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
access_log /var/log/nginx/cloudshop.access.log;
error_log /var/log/nginx/cloudshop.error.log warn;
location /health {
proxy_pass http://cloudshop_api;
access_log off;
}
location / {
proxy_pass http://cloudshop_api;
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 3s;
proxy_send_timeout 15s;
proxy_read_timeout 15s;
}
}
server {
listen 80;
server_name api.cloudshop.dev;
return 301 https://$host$request_uri;
}Nota de segurança: Não repasse cabeçalhos X-Forwarded-* vindos do cliente sem sobrescrevê-los: eles podem ser falsificados para burlar controles.
Diagnóstico de 5xx
bash
sudo nginx -t && sudo systemctl reload nginx
sudo tail -50 /var/log/nginx/cloudshop.error.log
# 502: o upstream aceita conexao?
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/health
ss -tulpn | grep :3000
systemctl status cloudshop-api --no-pager
# 504: quanto tempo a rota realmente leva?
curl -s -o /dev/null -w 'ttfb:%{time_starttransfer} total:%{time_total}\n' http://127.0.0.1:3000/orders
# taxa de erro por status no access log
awk '{print $9}' /var/log/nginx/cloudshop.access.log | sort | uniq -c | sort -rn | headUpstream com dois backends e failover
nginx
upstream cloudshop_api {
server 127.0.0.1:3000 max_fails=3 fail_timeout=10s;
server 127.0.0.1:3001 max_fails=3 fail_timeout=10s;
keepalive 32; # reutiliza conexoes com o backend
}
server {
listen 443 ssl http2;
server_name api.cloudshop.dev;
location / {
proxy_pass http://cloudshop_api;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 15s; # acima do p99 medido da API
}
}Diagnóstico rápido de 5xx
bash
sudo nginx -t && sudo systemctl reload nginx
sudo tail -n 50 /var/log/nginx/error.log | grep -E 'upstream|connect\(\)'
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# 1520 200 / 37 502 <- proporcao de erros
curl -sS http://127.0.0.1:3000/health # testa o upstream sem o proxyPor que isso importa
Saber diferenciar 502, 503 e 504 sob pressão é literalmente uma pergunta de entrevista e uma tarefa de plantão.
Erro comum
Aumentar proxy_read_timeout para 300s e chamar isso de correção do 504.
Dica de produção
Timeout do proxy sempre menor que o do cliente, e a aplicação deve ter timeout para suas próprias dependências.
Alerta de segurança
Oculte a versão do servidor (server_tokens off) e aplique rate limit em rotas de autenticação.
Pergunta de entrevista
Nginx retorna 502 apenas após deploys. Qual é a causa mais provável e como confirmar?
Glossário
- upstream
- Conjunto de servidores backend para onde o proxy encaminha requisições.
- keepalive
- Reuso de conexões TCP com o upstream, reduzindo latência.
- upstream
- Servidor de aplicação para o qual o proxy repassa as requisições.
- reload
- Recarregar configuração sem derrubar conexões ativas.
- round-robin
- Distribuição de requisições em rodízio entre os backends.
Conexão com o CloudShop
Colocar o Nginx na frente da API e do frontend do CloudShop com TLS e timeouts definidos.
Quiz da aula
1. O upstream aceitou a conexão mas demorou 40s. Qual status o Nginx retorna com read_timeout de 15s?
2. O log mostra 'upstream timed out while reading response header'. Qual status o cliente viu?
3. Qual comando valida a configuração antes de aplicar?
Minhas anotações
Salvo automaticamente neste navegador.