Resolvendo Problemas de Timeout 504 Gateway e Timeout do Cliente no Nginx

Domine os timeouts do Nginx, incluindo o temido 504 Gateway Timeout, aprendendo a ajustar diretivas críticas de proxy. Este guia detalha como aumentar o `proxy_read_timeout`, otimizar o buffering e usar logs de erro para diagnosticar falhas de comunicação entre o Nginx e servidores upstream para um tratamento robusto de conexões.

Resolvendo Problemas de Timeout 504 Gateway e Timeout do Cliente no Nginx

Um erro 504 Gateway Timeout no Nginx significa que o Nginx estava atuando como proxy ou gateway e não obteve uma resposta do serviço upstream a tempo. O upstream pode ser uma aplicação Node.js, Gunicorn, PHP-FPM, outro serviço Nginx, uma API interna ou um balanceador de carga.

A correção tentadora é aumentar todos os timeouts para cinco minutos e seguir em frente. Às vezes, um timeout mais longo é a medida certa a curto prazo, especialmente para relatórios, importações ou trabalhos exclusivos de administradores. Mas, se uma solicitação normal de usuário precisar de mais tempo do que o Nginx atualmente permite, você também deve perguntar por que o backend está lento, se a solicitação deve ser assíncrona e se outro proxy no caminho tem um timeout mais curto de qualquer maneira.


Entendendo o Erro 504 Gateway Timeout

Um erro 504 Gateway Timeout ocorre quando o Nginx, atuando como proxy reverso ou gateway, não recebe uma resposta em tempo hábil do servidor upstream para o qual está encaminhando as solicitações. Em termos simples: o Nginx perguntou ao backend por uma resposta, esperou pelo tempo configurado e desistiu porque nenhuma resposta chegou.

Isso é diferente de um 502 Bad Gateway, onde o Nginx recebeu uma resposta inválida ou prematuramente encerrada do upstream, e de um 503 Service Unavailable, que geralmente significa que um serviço está intencionalmente indisponível ou sobrecarregado. A distinção é importante porque um 504 aponta para espera, tempo e latência do upstream.

Diretivas Chave que Controlam os Timeouts do Upstream

Ao fazer proxy de solicitações, o Nginx usa várias diretivas críticas, localizadas principalmente nos blocos http, server ou location, ou especificamente dentro de um bloco upstream. Ajustar esses valores é o método principal para resolver erros 504.

1. proxy_connect_timeout

Isso define o timeout para estabelecer uma conexão com o servidor upstream. Se o Nginx não conseguir conectar dentro deste período, ele retorna um erro de timeout.

Padrão: 60 segundos

proxy_connect_timeout 60s;

2. proxy_send_timeout

Isso define o timeout para o tempo entre duas operações de escrita sucessivas para o servidor upstream. Isso é relevante ao enviar um corpo de solicitação grande.

Padrão: 60 segundos

proxy_send_timeout 60s;

3. proxy_read_timeout (A Correção Mais Comum para 504s)

Isso define o timeout para aguardar uma resposta do servidor upstream após o envio dos cabeçalhos da solicitação. Se a aplicação backend demorar muito para processar a solicitação e gerar um corpo de resposta, esta é a diretiva que precisa ser aumentada.

Padrão: 60 segundos

# Exemplo: Aumentando o timeout de leitura para 120 segundos para uma API lenta
proxy_read_timeout 120s;

Se sua aplicação excede frequentemente o padrão, aumente este valor com cautela e continue investigando. Um valor muito alto pode manter as conexões do cliente abertas enquanto o backend já está não saudável.


Lidando com Timeouts do Lado do Cliente

Timeouts do lado do cliente são uma falha diferente. O navegador, aplicativo móvel, balanceador de carga, CDN ou serviço de chamada desiste antes que o Nginx termine a resposta. Nesse caso, o usuário pode ver um erro do navegador ou um erro de gateway de uma camada na frente do Nginx, enquanto o Nginx pode registrar uma conexão fechada em vez de um 504 limpo.

Se você está experimentando timeouts do cliente antes do Nginx registrar um 504, você precisa olhar para a conexão entre o cliente e o Nginx.

1. Keepalive do Lado do Cliente

Se o cliente fechar a conexão prematuramente, o Nginx pode receber um erro ou o cliente pode simplesmente atingir o timeout aguardando dados.

Se o cliente for outro proxy ou balanceador de carga, verifique suas configurações de timeout em relação ao Nginx e ao backend. O timeout mais curto na cadeia geralmente vence. Um padrão comum é: CDN espera 100 segundos, balanceador de carga espera 60 segundos, Nginx espera 180 segundos, backend leva 120 segundos. Os usuários ainda falham em 60 segundos porque o balanceador de carga desiste primeiro.

2. send_timeout do Nginx

Esta diretiva controla quanto tempo o Nginx esperará para que o cliente reconheça ou receba dados (o tempo entre duas operações de escrita sucessivas para o cliente).

Padrão: 60 segundos

# Defina isso se os clientes estiverem atingindo o timeout enquanto o Nginx está enviando a resposta
send_timeout 120s;

Otimizando o Buffering para Respostas Grandes

Às vezes, o backend começa a responder, mas a entrega ainda é lenta porque a resposta é enorme, o cliente é lento ou o Nginx precisa armazenar em buffer mais do que o esperado. Isso é comum com exportações CSV geradas, downloads de mídia roteados através de um aplicativo ou APIs que retornam payloads JSON muito grandes.

O Nginx usa buffers para armazenar temporariamente os dados recebidos do upstream antes de enviá-los ao cliente. Se a resposta for muito grande, esses buffers podem ser excedidos, levando a um tratamento complexo ou latência percebida.

Diretivas Chave de Buffering

Elas geralmente são definidas dentro do bloco location ou server:

Diretiva Propósito
proxy_buffers Define o número e o tamanho dos buffers usados para ler a resposta do upstream. Formato: número tamanho;
proxy_buffer_size Define o tamanho do primeiro buffer, que é usado para ler o cabeçalho da resposta.
proxy_max_temp_file_size Se a resposta exceder os buffers disponíveis, o Nginx escreve em arquivos temporários. Isso define o tamanho máximo para esses arquivos temporários.

Exemplo de Configuração para Alto Volume/Respostas Grandes:

location /api/heavy_report {
    proxy_pass http://backend_app;

    # Aumentar o timeout de leitura
    proxy_read_timeout 180s;

    # Ajustar o buffering para corpos de resposta potencialmente grandes
    # Usar 8 buffers, cada um de até 1MB (1024k)
    proxy_buffers 8 1024k;
    proxy_buffer_size 256k;

    # Permitir arquivos temporários de até 500MB se os buffers transbordarem
    proxy_max_temp_file_size 500m;
}

Se a resposta do seu backend for genuinamente enorme, considere servir um arquivo gerado a partir de armazenamento de objetos ou armazenamento estático em vez de manter a solicitação aberta através do aplicativo. Para exportações, um padrão comum é: enfileirar o trabalho, gerar o arquivo e, em seguida, permitir que o usuário faça o download de uma URL estática quando estiver pronto.


Etapas de Solução de Problemas e Análise de Logs

Resolver timeouts requer identificar onde ocorreu a parada: Cliente -> Nginx, ou Nginx -> Backend.

Etapa 1: Verificar os Logs de Erro do Nginx

O log de erros do Nginx é sua fonte definitiva para determinar se o Nginx atingiu o timeout aguardando o backend.

Procure por entradas contendo frases como:

  • upstream timed out (110: Connection timed out)
  • upstream prematurely closed connection while reading response header from upstream

Se você vir estas, o problema está no proxy_read_timeout ou no tempo de processamento do backend.

Também procure por client prematurely closed connection. Isso geralmente significa que o cliente ou um proxy na frente do Nginx desistiu primeiro. Nesse caso, aumentar apenas o proxy_read_timeout não ajudará o usuário.

Etapa 2: Verificar os Logs da Aplicação Backend

Se o Nginx atingir o timeout (logs indicam 504), verifique imediatamente os logs do serviço upstream (por exemplo, logs do PHP-FPM, logs do Gunicorn, logs do servidor de aplicação Java). Você precisa confirmar se a solicitação chegou ao backend e quanto tempo levou para ser concluída.

  • Se os logs do backend mostrarem que a solicitação levou mais tempo do que seu proxy_read_timeout configurado, aumente o timeout do Nginx.
  • Se os logs do backend mostrarem que a solicitação foi concluída rapidamente, o problema pode ser latência de rede entre o Nginx e o backend, ou um timeout do cliente mal configurado voltado para o Nginx.

Etapa 3: Usar o Cabeçalho X-Upstream-Response-Time (Opcional)

Para diagnósticos detalhados, você pode registrar o tempo exato que o upstream levou para responder usando a variável $upstream_response_time no formato do seu log de acesso. Isso ajuda a confirmar o desempenho real do backend.

No seu nginx.conf:

log_format proxy_detailed '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" $request_time $upstream_response_time';

access_log /var/log/nginx/access.log proxy_detailed;

Ao analisar $upstream_response_time, você pode ver a duração precisa que o Nginx esperou, independentemente das próprias configurações de timeout do Nginx.

Para um teste rápido e único, chame o upstream diretamente do host do Nginx:

time curl -sS -o /dev/null -w 'status=%{http_code} total=%{time_total}\n' http://127.0.0.1:3000/slow-route

Se a chamada direta ao upstream já for lenta, o Nginx está apenas relatando o problema. Se a chamada direta for rápida, mas a solicitação com proxy atingir o timeout, inspecione a configuração do proxy, a resolução de DNS, a rede do contêiner, o TLS entre serviços internos ou outro salto entre o Nginx e o aplicativo.


Aplique a Menor Mudança Útil

Uma correção razoável de produção geralmente se parece com isso:

location /api/reports/ {
    proxy_pass http://backend_app;
    proxy_connect_timeout 10s;
    proxy_send_timeout 60s;
    proxy_read_timeout 180s;
}

Isso aumenta o timeout de leitura apenas para o endpoint de relatório lento. Não faz com que cada solicitação no site espere três minutos. Para uma rota de login, rota de checkout, health check ou endpoint de API pública, um timeout longo pode tornar as falhas mais dolorosas porque os clientes esperam mais por uma solicitação que provavelmente não se recuperará.

Para PHP-FPM, o equivalente pode envolver diretivas FastCGI:

location ~ \.php$ {
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    fastcgi_read_timeout 120s;
    include fastcgi_params;
}

Lembre-se de que PHP, Python, Node.js, servidores de aplicação, filas, bancos de dados, CDNs e balanceadores de carga podem ter suas próprias configurações de timeout. O Nginx não pode fazer um backend continuar funcionando após o timeout do próprio worker do backend matar a solicitação.

Após fazer qualquer alteração de configuração (por exemplo, aumentar timeouts ou ajustar tamanhos de buffer), sempre teste a sintaxe da configuração e recarregue o Nginx:

sudo nginx -t
sudo systemctl reload nginx

Em seguida, observe os logs do Nginx e do upstream enquanto repete a mesma solicitação:

sudo tail -f /var/log/nginx/error.log

A melhor correção de timeout deixa você com um motivo claro para a mudança: esta rota legitima leva até dois minutos, este upstream agora tem limites correspondentes e solicitações lentas são visíveis nos logs ou métricas. Qualquer coisa menos é um patch temporário, e patches temporários devem ser rotulados como tal em sua revisão de configuração ou notas de incidente.