Resolver o nginx 502 Bad Gateway: causas e soluções

Publicado a 18 min de leitura

502 Bad Gateway significa que o nginx não recebeu uma resposta válida do backend. As cinco causas mais frequentes, a linha certa no log de erros e como comprovar que a correção resultou mesmo.

O que significa realmente "502 Bad Gateway"

Um 502 não vem da sua aplicação, vem do nginx. O nginx aceitou o pedido, encaminhou-o para um backend (PHP-FPM, Node, Python, outro servidor web) e não recebeu de lá nenhuma resposta aproveitável. É por isso que a página de erro não mostra nada de útil.

Distinguir este código dos seus vizinhos poupa muito tempo numa emergência:

  • 500 Internal Server Error: o backend respondeu, e a resposta foi um erro. A causa está no código da aplicação. Leia o log da aplicação, não o do nginx.
  • 502 Bad Gateway: a ligação ao backend não chegou a estabelecer-se, ou interrompeu-se antes de existir uma resposta completa.
  • 504 Gateway Time-out: a ligação estava de pé, o backend é que ficou demasiado tempo calado e o nginx perdeu a paciência.

Esta distinção é a alavanca mais importante nos casos de tempo limite excedido, porque a mesma página lenta aparece ora como 502 ora como 504, consoante quem desiste primeiro. Voltamos ao assunto mais abaixo.

A situação dos pacotes no Debian 13, Debian 12, Ubuntu 24.04 e Ubuntu 22.04

Perante erros 502, o nginx comporta-se da mesma forma nos quatro sistemas e as diretivas têm nomes idênticos. As diferenças estão quase todas do lado do PHP, e é precisamente daí que nasce a maioria dos 502 depois de uma mudança de distribuição.

SistemanginxPHPNome do serviçoSocket
Debian 13 (Trixie)1.26.38.4php8.4-fpm/run/php/php8.4-fpm.sock
Debian 12 (Bookworm)1.22.18.2php8.2-fpm/run/php/php8.2-fpm.sock
Ubuntu 24.04 LTS1.24.08.3php8.3-fpm/run/php/php8.3-fpm.sock
Ubuntu 22.04 LTS1.18.08.1php8.1-fpm/run/php/php8.1-fpm.sock

Em todos os comandos seguintes, substitua o número de versão pelo do seu sistema. Todos os exemplos partem de uma shell root; caso contrário, coloque sudo à frente. Para saber que versão está instalada basta olhar para os binários do FPM, mesmo que o serviço nem sequer arranque:

ls /usr/sbin/php-fpm*
ls /etc/php/

Primeiro o log de erros: encontrar a linha certa

O erro mais comum no diagnóstico é procurar no log errado. O nginx tem um log de erros global e, muitas vezes, um log próprio por cada host virtual. Qual dos ficheiros vale está na configuração:

grep -Rn "error_log" /etc/nginx/nginx.conf /etc/nginx/sites-enabled/

Repare no -R maiúsculo. No Debian e no Ubuntu, em /etc/nginx/sites-enabled/ existem exclusivamente symlinks para sites-available, e o GNU grep, com o -r minúsculo, não segue nenhum symlink durante a descida recursiva. Com -rn obtém apenas as ocorrências de nginx.conf, enquanto a linha error_log do próprio vhost permanece invisível: precisamente aquela que interessa num caso de 502, porque o log global deixa de conter o erro FastCGI assim que o vhost redireciona o registo. Quem preferir ficar pelo -r faz grep diretamente aos diretórios de origem:

grep -rn "error_log" /etc/nginx/nginx.conf /etc/nginx/sites-available/ /etc/nginx/conf.d/

Sem indicação própria no bloco server, tudo vai parar a /var/log/nginx/error.log. O caminho mais fiável até à linha certa passa por acompanhar o log em direto: mantenha o log aberto num terminal, desencadeie o pedido num segundo terminal e observe as linhas que aparecem de novo.

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

Em alternativa, filtre pela marca temporal. O nginx escreve a hora local no formato 2026/07/26 09:14:22, não em UTC. Comparar com um relógio noutro fuso horário falha com regularidade.

Uma linha de 502 segue sempre o mesmo padrão. Exemplo:

2026/07/26 09:14:22 [error] 812#812: *3 connect() to unix:/run/php/php8.2-fpm.sock
failed (2: No such file or directory) while connecting to upstream,
client: 203.0.113.7, server: example.com,
request: "GET /index.php HTTP/1.1",
upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:", host: "example.com"

Quatro elementos carregam toda a informação:

  1. A chamada de sistema: connect(), recv(), send(). connect() significa que nunca se chegou a estabelecer uma ligação. recv() significa que a ligação existia e que depois se interrompeu.
  2. O número de erro entre parênteses, ver a tabela abaixo. É esse o verdadeiro diagnóstico.
  3. A fase: while connecting to upstream por oposição a while reading response header from upstream. O primeiro é um problema de acessibilidade, o segundo um problema de tempo de execução ou de crash.
  4. O campo upstream:. Aí está o caminho ou o endereço que o nginx realmente usou. Não aquilo que supõe estar na configuração, mas aquilo que está de facto carregado.
MensagemSignificadoSecção
2: No such file or directoryO ficheiro de socket não existeServiço parado ou caminho errado
13: Permission deniedO socket existe, mas o nginx não lhe pode acederPermissões
111: Connection refusedNada está à escuta no endereço e na portaBackend inacessível
110: Connection timed outSem resposta dentro do prazoTempo limite excedido
104: Connection reset by peerO processo do backend morreu a meio do pedidoCrashes e limites
11: Resource temporarily unavailableFila de espera do socket cheiaCrashes e limites

No nginx, a linha relativa a 13: Permission denied traz muitas vezes o nível [crit] em vez de [error]. Quem filtra apenas por [error] não dá por ela. Filtre antes pelo texto:

grep -n "upstream" /var/log/nginx/error.log

A segunda metade da verdade está no log do PHP-FPM, por predefinição em /var/log/php8.2-fpm.log. Em casos de crash e de limites atingidos é aí que está a justificação, ao passo que o nginx apenas vê o sintoma.

Causa 1: o PHP-FPM não está a correr

O clássico número de erro 2. Verifique primeiro o estado do serviço:

systemctl is-active php8.2-fpm
systemctl status php8.2-fpm --no-pager -l

O is-active responde com uma única palavra, o que chega para um script. Se surgir inactive ou failed, vá buscar o motivo ao journal, e de preferência com uma janela temporal em vez das últimas dez linhas:

journalctl -u php8.2-fpm --since "30 min ago" --no-pager

Muitas vezes a causa é uma configuração de pool danificada que ficou para trás depois de um reload. O FPM tem um teste de sintaxe próprio, que corre sem reiniciar o serviço:

php-fpm8.2 -t

Erros de arranque típicos, na sua formulação literal, e o que significam:

  • ERROR: [pool www] cannot get uid for user 'webuser': o utilizador de sistema indicado em user = já não existe, por exemplo depois de uma migração.
  • ERROR: unable to bind listening socket for address '/run/php/php8.2-fpm.sock': No such file or directory (2): falta o diretório /run/php. Ele fica num tmpfs e é criado no arranque do serviço. Quem apontar o listen para um caminho fora dele tem de tratar da criação do diretório.
  • ERROR: An another FPM instance seems to already listen on ...: um processo sobrante de um reinício falhado continua agarrado ao socket.

Como reconhecer que está mesmo resolvido: não é pelo facto de o systemctl restart ter corrido sem produzir saída. Um master do FPM arranca mesmo quando nenhum processo de trabalho consegue aceitar pedidos. O que conta é que o socket esteja visível no sistema e que o FPM responda nele.

ss -lx | grep php

Para o verdadeiro teste de resposta, ative em /etc/php/8.2/fpm/pool.d/www.conf a linha ping.path = /ping, recarregue o FPM e interrogue o socket diretamente, sem passar de todo pelo nginx:

apt-get install -y libfcgi-bin
SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET \
  cgi-fcgi -bind -connect /run/php/php8.2-fpm.sock

Se vier pong de volta, o lado do PHP está em ordem e o erro situa-se entre o nginx e o socket. Se não vier nada, nem vale a pena continuar a procurar no nginx.

Causa 2: caminho de socket errado

No Debian e no Ubuntu esta é, de longe, a causa mais frequente: o socket leva a versão do PHP no nome, a configuração do nginx fixa esse nome de forma rígida, e uma atualização de distribuição separa os dois.

Em concreto: uma atualização de Debian 12 para Debian 13 leva o PHP de 8.2 para 8.4. O socket antigo /run/php/php8.2-fpm.sock desaparece, mas continua escrito no ficheiro do vhost. O resultado é um 502 em cada uma das páginas PHP, logo a seguir ao reinício. O mesmo acontece na passagem do Ubuntu 22.04 para 24.04 (8.1 para 8.3).

Uma segunda armadilha está na configuração de exemplo que vem incluída. Em /etc/nginx/sites-available/default existe um bloco comentado cujo fastcgi_pass aponta para uma versão de PHP que há anos deixou de ser atual. Quem se limita a descomentar essas linhas acaba de criar o 502.

Compare os dois lados. O que o nginx quer usar:

grep -Rn "fastcgi_pass" /etc/nginx/

O que o FPM oferece de facto:

grep -n "^listen *=" /etc/php/*/fpm/pool.d/*.conf

O acréscimo *= no padrão de pesquisa é intencional: exige, depois de listen, um número qualquer de espaços e a seguir um sinal de igual. Um simples ^listen apanharia também listen.owner, listen.group e listen.mode, e a linha procurada perder-se-ia no meio das ocorrências. Já o caractere universal /etc/php/*/ está correto assim, pois cobre todas as versões de PHP instaladas. E o que existe no sistema em execução:

ls -l /run/php/

As três saídas têm de mostrar o mesmo caminho. Importante: use grep -R sobre /etc/nginx/ e não apenas sobre o ficheiro de que desconfia. Os fragmentos integrados através de include são um esconderijo apreciado, tal como ficheiros antigos em sites-available que continuam ativos por causa de um symlink esquecido em sites-enabled. Também aqui vale a regra: só o -R maiúsculo segue esses symlinks e lhe mostra, assim, que ficheiro está realmente ativo.

ls -l /etc/nginx/sites-enabled/

Antes de alterar seja o que for, faça uma cópia. Custa dois segundos e, na dúvida, poupa-lhe um restauro a partir do backup:

mkdir -p /root/backups
cp -a /etc/nginx/sites-available/default /root/backups/default.bak

Quem intervém várias vezes faz melhor em acrescentar uma marca temporal (default.bak.$(date +%F-%H%M)), porque o cp -a sobrescreve sem aviso um .bak já existente.

Depois da correção, teste sempre primeiro e só depois recarregue. Use reload em vez de restart, para que as ligações existentes não caiam:

nginx -t
systemctl reload nginx

Atenção: o nginx -t verifica exclusivamente a sintaxe. Um caminho de socket que não existe conta como configuração perfeitamente válida. Um syntax is ok a verde não é, por isso, prova de que o 502 desapareceu.

Causa 3: permissões do socket

Número de erro 13. O socket está lá, o nginx é que não o pode abrir. No Debian e no Ubuntu, o nginx corre com o utilizador www-data, e o pool predefinido do FPM cria o socket em conformidade. Isso vê-se no ficheiro do pool:

grep -n "listen.owner\|listen.group\|listen.mode" /etc/php/*/fpm/pool.d/*.conf

Com listen.owner = www-data, listen.group = www-data e o modo 0660, a articulação funciona sem qualquer intervenção. As coisas podem correr mal em três situações:

  • Um pool próprio por projeto. Se user e group forem definidos para um utilizador do projeto, o listen.group tem ainda assim de ser um grupo a que o nginx pertença. O habitual é listen.owner = utilizadorprojeto em conjunto com listen.group = www-data.
  • Socket fora de /run. Não basta que o ficheiro de socket esteja acessível: cada diretório no caminho até lá precisa da permissão de execução para o nginx. Um socket numa pasta pessoal com o modo 0700 não está acessível a ninguém a não ser ao proprietário.
  • nginx com o user alterado em /etc/nginx/nginx.conf.

Confirme a suspeita sem adivinhar, tentando o acesso exatamente com o utilizador que dele precisa em produção:

id www-data
sudo -u www-data test -w /run/php/php8.2-fpm.sock && echo "acesso disponível" || echo "sem acesso"

Ainda mais conclusiva é a chamada cgi-fcgi da secção anterior, igualmente precedida de sudo -u www-data. Se o FPM responder como root mas não como www-data, o diagnóstico é inequívoco.

Defina os valores no ficheiro do pool, não com chmod sobre o ficheiro de socket. Um chmod 666 dura exatamente até ao reinício seguinte do FPM: nessa altura o FPM volta a criar o socket com as permissões configuradas e o erro regressa, normalmente no pior momento possível.

No Debian e no Ubuntu o AppArmor está ativo. O perfil para o nginx que vem incluído não é imposto de origem, mas pode ter sido ativado por modelos de hardening. Se uma mensagem 13 persistir apesar de as permissões estarem corretas, vale a pena consultar aa-status e journalctl -k | grep DENIED.

Causa 4: tempo limite excedido em pedidos longos

É aqui que um método rigoroso se separa da adivinhação, porque o simples esgotar do prazo do nginx produz um 504, não um 502. Quando um pedido longo termina em 502, foi quase sempre o PHP-FPM que eliminou antes o processo de trabalho, e o nginx apenas viu uma ligação cortada. No log aparece então, tipicamente:

recv() failed (104: Connection reset by peer) while reading response header from upstream

Três prazos atuam em simultâneo, e é a ordem entre eles que decide o código de estado:

  1. max_execution_time no php.ini, 30 segundos por predefinição em modo FPM. Conta apenas o tempo de execução do script. O tempo de espera em chamadas de sistema, por exemplo numa consulta à base de dados que ficou pendurada, não conta no Linux. É por isso que este valor não salva ninguém precisamente no problema em que toda a gente espera que salve.
  2. request_terminate_timeout no ficheiro do pool, desativado de origem. Termina o processo de trabalho de forma abrupta, seja qual for a razão por que está pendurado. É este o valor que produz os 502.
  3. fastcgi_read_timeout no nginx, 60 segundos por predefinição. Quando se esgota, o resultado é um 504.

A ordem útil é crescente de dentro para fora, para que atue primeiro a camada que ainda consegue produzir uma mensagem de erro compreensível. Por exemplo 60, depois 75, depois 90 segundos. Ordenados ao contrário, o que obtém são 502 em vez de erros de PHP legíveis.

grep -rn "request_terminate_timeout" /etc/php/*/fpm/pool.d/*.conf

Aquilo que o FPM eliminou fica registado em texto claro no log dele:

WARNING: [pool www] child 1234, script '/var/www/html/import.php'
(request: "POST /import.php") execution timed out (76.271849 sec), terminating

Antes de aumentar prazos, descubra para onde vai o tempo. O FPM traz para isso um log próprio, que escreve uma pilha de chamadas PHP completa quando o limite é ultrapassado. Ative-o no ficheiro do pool:

slowlog = /var/log/php-fpm-slow.log
request_slowlog_timeout = 5s

Depois de um systemctl reload php8.2-fpm, no pedido lento seguinte fica ali registada a função, com número de linha, que está pendurada. Na prática, em quatro de cada cinco casos trata-se de uma consulta à base de dados sem índice ou de uma chamada a uma interface de programação externa sem prazo próprio. Aumentar os prazos apenas prolonga o tempo até ao erro e bloqueia ainda mais processos de trabalho.

Causa 5: backend inacessível

Afeta qualquer backend contactado por TCP: o FPM na porta 9000, uma aplicação Node, um serviço Java, um container. A mensagem indicadora é o número de erro 111.

connect() to 127.0.0.1:3000 failed (111: Connection refused) while connecting to upstream

Verifique primeiro se há sequer alguma coisa à escuta e, sobretudo, em quê:

ss -ltnp

Este comando lista exclusivamente sockets TCP, e daí nasce um equívoco muito comum: um pool de PHP-FPM na configuração de origem escuta num socket Unix em /run/php/ e não aparece de todo nesta lista, ainda que esteja a funcionar sem falhas. Só assim se torna visível:

ss -lxn | grep php-fpm
ls -l /run/php/

Para o FPM, o ss -ltnp só é conclusivo, portanto, se o pool tiver sido deliberadamente passado para TCP com listen = 127.0.0.1:9000. Já para backends em Node, Java ou containers é exatamente o comando certo.

Três armadilhas que raramente constam dos guias:

  • O localhost resolve primeiro para ::1. Se no nginx estiver proxy_pass http://localhost:3000; mas a aplicação só escutar em 127.0.0.1, o nginx tenta o endereço IPv6 e recebe "Connection refused". O serviço corre, a porta está aberta e mesmo assim há 502. Solução: escrever 127.0.0.1 por extenso no nginx, ou ligar a aplicação a ambas as famílias de endereços.
  • O nginx resolve os nomes uma única vez, no carregamento. Se no proxy_pass estiver um nome de máquina, o nginx guarda o endereço. Se o backend mudar de endereço IP, por exemplo um container reiniciado, os pedidos ficam a bater no vazio até ao reload seguinte.
  • Firewall no caminho de volta. Com um backend noutro servidor aparece 113: No route to host ou um tempo limite excedido, em vez de "Connection refused". Verifique com ufw status e com um teste de ligação direto a partir do servidor nginx.

Se for usado um bloco upstream com vários destinos, junta-se-lhe uma mensagem própria:

no live upstreams while connecting to upstream

Significa que o nginx retirou de circulação todos os destinos durante fail_timeout, depois de tentativas falhadas repetidas. Mesmo depois de reparar o backend, é preciso esperar que esse prazo termine para que os pedidos voltem a passar. Um systemctl reload nginx repõe o estado de imediato.

O 502 que não encaixa em nenhuma das cinco causas

Dois casos parecem uma avaria sem o serem, e por isso custam muito mais tempo do que a média.

Cabeçalho de resposta demasiado grande. A aplicação corre sem falhas, apenas alguns pedidos devolvem 502:

upstream sent too big header while reading response header from upstream

A origem está em cookies grandes ou em atributos de sessão nos cabeçalhos: o buffer do nginx é pequeno demais. No bloco server ou location:

fastcgi_buffer_size 32k;
fastcgi_buffers 8 16k;
fastcgi_busy_buffers_size 64k;

Com proxy_pass, as diretivas chamam-se proxy_buffer_size e proxy_buffers. É típico que só os utilizadores com sessão iniciada sejam afetados, enquanto a página inicial carrega sem problemas.

Processos de trabalho esgotados. Sob carga, no log do FPM aparece:

WARNING: [pool www] server reached pm.max_children setting (5), consider raising it

Os novos pedidos ficam então na fila de espera do socket. Se também essa encher, o nginx comunica 11: Resource temporarily unavailable. Antes de aumentar o pm.max_children, faça uma conta rápida: memória disponível a dividir pelo consumo real de um processo de trabalho. Um valor demasiado alto troca os 502 por um estado do sistema em que a memória se esgota, e isso atinge também a base de dados.

Crashes. Linhas com exited on signal 11 (SIGSEGV) apontam para uma extensão de PHP defeituosa, muitas vezes depois de uma mudança de versão do PHP com módulos sobrantes da versão anterior.

Quando a intervenção não resolve: o caminho de volta

Duas regras mantêm os estragos pequenos. Primeira: uma alteração de cada vez, com cópia do ficheiro original em /root/backups, nunca no diretório web. Segunda: verificar depois de cada passo, em vez de mudar três coisas ao mesmo tempo e ficar depois sem saber qual delas ajudou.

Se o nginx deixar de funcionar por completo depois de uma alteração, reponha a cópia e recarregue:

cp -a /root/backups/default.bak /etc/nginx/sites-available/default
nginx -t
systemctl reload nginx

Se o nginx deixar de arrancar após um restart, o systemctl status nginx raramente diz o suficiente. Mais conclusivo:

journalctl -u nginx --since "10 min ago" --no-pager

O motivo mais frequente para um restart falhado com uma configuração sintaticamente impecável é a porta 80 ou 443 estar ocupada, normalmente por um processo da execução anterior. O ss -ltnp | grep ':80' mostra o culpado.

Como saber que o problema está realmente resolvido

Um comando sem mensagem de erro não prova rigorosamente nada. O systemctl reload também fica calado quando, na prática, nada mudou, e o nginx -t só verifica sintaxe. Sólidas são estas quatro provas:

  1. Consultar o código de estado diretamente no servidor, para que nem uma cache nem um serviço a montante falseiem o resultado:
    curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1/
    O esperado é 200, não 502. Com vários hosts virtuais, indique o nome: curl -H "Host: example.com" ...
  2. O log de erros mantém-se em silêncio. Esvazie-o antes do teste com truncate -s 0 /var/log/nginx/error.log, desencadeie vários pedidos e volte a consultá-lo. Um ficheiro vazio é que é a verdadeira prova.
  3. O FPM responde no socket, sem passar pelo nginx, através de cgi-fcgi e como www-data. Assim resolve-se num só passo a questão das permissões e a do caminho.
  4. Um reinício não muda nada. É o ponto mais importante e o mais vezes saltado. Muitas medidas imediatas (permissões definidas à mão, diretórios criados manualmente em /run, um serviço iniciado mas não ativado) não sobrevivem a um reinício. Verifique o systemctl is-enabled php8.2-fpm nginx e reinicie o servidor uma vez de forma controlada, enquanto ainda está a acompanhar, em vez de deixar isso para a próxima janela de manutenção.

Nos servidores root KVM e nos servidores dedicados da KernelHost, este reinício faz-se na área de cliente, com acesso à consola incluído, mesmo quando o serviço web está inacessível nesse momento. Os servidores estão no datacenter maincubes em Frankfurt am Main (TÜV TIER3+), ligados a uma rede própria com proteção DDoS. Para aprofundar: resolver o nginx 504 Gateway Time-out e calcular corretamente o pm.max_children do PHP-FPM.

Lista de verificação rápida para a emergência

  1. tail -f /var/log/nginx/error.log, desencadear o pedido, anotar o número de erro.
  2. Número 2 ou 111: o serviço está a correr? o caminho está certo? Compare ss -lx | grep php com grep -Rn "fastcgi_pass" /etc/nginx/.
  3. Número 13: permissões no ficheiro do pool, não via chmod.
  4. Número 104 ou 110: ler o log do FPM e o slowlog, e só depois falar de prazos.
  5. Mensagem "too big header": aumentar os tamanhos dos buffers.
  6. Depois da correção: esvaziar o log, voltar a testar, reiniciar o servidor uma vez.

Perguntas frequentes

Porque é que vejo um 502 e não um 504, se a página apenas está lenta?
Quando o prazo do nginx se esgota (fastcgi_read_timeout, 60 segundos por predefinição), o nginx responde com 504 Gateway Time-out. Em pedidos longos, um 502 surge tipicamente quando o PHP-FPM termina antes, de forma abrupta, o processo de trabalho, normalmente por causa do request_terminate_timeout. O nginx passa a ver apenas uma ligação interrompida e regista 'recv() failed (104: Connection reset by peer)'. Ordene os prazos de forma crescente, de dentro para fora, e obtém erros de PHP legíveis em vez de 502.
Depois da atualização para o Debian 13, todas as páginas PHP dão 502. O que tenho de mudar?
O socket leva a versão do PHP no nome. O Debian 13 traz o PHP 8.4 e o socket chama-se /run/php/php8.4-fpm.sock, mas na configuração do nginx continua o caminho do Debian 12 com a 8.2. Ajuste o fastcgi_pass em todos os ficheiros de vhost ativos, confirme com 'grep -Rn "fastcgi_pass" /etc/nginx/' e 'ls -l /run/php/' que ambos os lados mostram o mesmo caminho e recarregue o nginx a seguir. Na passagem do Ubuntu 22.04 para 24.04 o efeito é o mesmo (8.1 para 8.3).
O 'nginx -t' chega como prova de que o erro está corrigido?
Não. O 'nginx -t' verifica exclusivamente a sintaxe da configuração. Um caminho de socket que nem sequer existe no sistema está sintaticamente correto e continua a devolver um 502 em cada pedido. Só é sólido um teste do código de estado no próprio servidor, por exemplo 'curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1/', em conjunto com um log de erros que se mantenha vazio durante o teste.
Como encontro no log de erros a linha que corresponde ao meu 502?
Mantenha o 'tail -f /var/log/nginx/error.log' aberto num terminal e desencadeie o pedido num segundo terminal. As linhas que surgirem nesse momento são as certas. Tenha em conta que muitos vhosts têm um error_log próprio, o que se verifica com 'grep -Rn "error_log" /etc/nginx/nginx.conf /etc/nginx/sites-enabled/'. O -R maiúsculo é aqui decisivo, porque em sites-enabled só existem symlinks, que o -r minúsculo não segue, e nesse caso fica invisível precisamente a linha error_log do vhost. As mensagens sobre 'Permission denied' têm muitas vezes o nível [crit] em vez de [error], por isso é melhor filtrar pela palavra 'upstream'.
O 502 só acontece com utilizadores com sessão iniciada, a página inicial carrega normalmente. A que se deve?
É quase sempre a mensagem 'upstream sent too big header while reading response header from upstream'. As sessões autenticadas trazem cookies maiores e cabeçalhos adicionais, que rebentam com o buffer de resposta do nginx. Aumente o fastcgi_buffer_size e o fastcgi_buffers no bloco server ou location, e com proxy_pass os correspondentes proxy_buffer_size e proxy_buffers.
Corrigi as permissões do socket com chmod, mas depois de um reinício o erro voltou. Porquê?
O PHP-FPM cria o ficheiro de socket de novo em cada arranque e aplica-lhe os valores de listen.owner, listen.group e listen.mode do ficheiro do pool. Um chmod feito à mão dura, por isso, apenas até ao arranque seguinte do serviço. Escreva as permissões em /etc/php/<versão>/fpm/pool.d/www.conf e recarregue o FPM.

nginx PHP-FPM 502 Bad Gateway Debian Ubuntu Resolução de problemas Servidor web Administração Linux