Páginas de Erro Personalizadas no Nginx: Melhore a Experiência do Usuário

Configure páginas de erro personalizadas úteis no Nginx para respostas 404, 403 e 50x sem ocultar falhas reais.

Páginas de Erro Personalizadas no Nginx: Melhore a Experiência do Usuário

Páginas de erro personalizadas no Nginx transformam uma falha bruta em um próximo passo claro. Elas não corrigem o link quebrado, o arquivo ausente ou o aplicativo upstream que travou. Elas fazem algo menor, mas ainda valioso: informam ao visitante o que aconteceu em linguagem simples e evitam que ele se sinta expulso do seu site.

Isso é importante durante erros comuns. Alguém segue um link antigo de documentação e recebe um 404. Um caminho de arquivo privado retorna 403. Seu aplicativo reinicia durante a implantação e o Nginx vê brevemente um 502. Sem uma página personalizada, os usuários podem ver uma resposta padrão do servidor que parece abrupta ou técnica. Com uma boa página estática, eles sabem se devem pesquisar, voltar, tentar novamente ou esperar.

As melhores páginas de erro são ferramentas operacionais simples. Elas são estáticas, rápidas, acessíveis e honestas. Elas não escondem interrupções do monitoramento e não expõem detalhes internos aos usuários.

Comece pelos erros que as pessoas realmente veem

Você não precisa criar uma página para cada código de status HTTP. Comece pelos mais comuns.

404 Não Encontrado é a primeira página a personalizar. Ela aparece quando a URL solicitada não corresponde a um arquivo, rota ou localização do Nginx que retorna conteúdo. Links antigos, posts renomeados, páginas de documentação excluídas e URLs digitadas manualmente levam a isso.

Uma página 404 útil diz algo como: "Não conseguimos encontrar essa página." Em seguida, oferece um caminho de volta para a página inicial, índice de documentação, área de produto ou página de pesquisa. Não culpe o usuário. A URL pode estar errada muito antes de ele clicar nela.

403 Proibido é diferente. O Nginx entendeu a solicitação, mas não a atenderá. As causas incluem permissões de arquivo, regras de acesso, listagem de diretório desabilitada, regras de permitir/negar IP ou requisitos de autenticação. Uma página 403 deve ser calma e curta. Se o recurso for privado, diga isso. Se os usuários precisarem de acesso, aponte para o login ou caminho de suporte correto.

Para sites com aplicativos, trate os erros 50x com cuidado:

  • 500 Erro Interno do Servidor geralmente significa que o aplicativo falhou ao processar a solicitação.
  • 502 Gateway Inválido geralmente significa que o Nginx não recebeu uma resposta válida do serviço upstream.
  • 503 Serviço Indisponível é útil para manutenção, sobrecarga ou um serviço deliberadamente indisponível.
  • 504 Tempo Limite do Gateway significa que o Nginx esperou muito tempo pela resposta upstream.

Um exemplo de painel SaaS: seu processo de aplicativo reinicia durante a implantação. Por alguns segundos, o Nginx não consegue se conectar ao upstream e os usuários veem um 502. Uma página personalizada pode dizer: "O painel está temporariamente indisponível. Atualize a página em um minuto." Isso não é perfeito, mas é mais claro do que um erro de gateway padrão.

Crie arquivos de erro estáticos

Mantenha as páginas de erro fora da cadeia de dependência do aplicativo. Se o banco de dados estiver inativo, a página 500 ainda deve carregar. Se o aplicativo Node, Python, Ruby ou PHP estiver com problemas, o Nginx ainda deve servir o fallback estático.

Um layout de arquivo simples pode ser:

/var/www/example.com/public/
  index.html
  assets/
/var/www/example.com/errors/
  404.html
  403.html
  50x.html

Mantenha o HTML leve. Evite scripts de terceiros, imagens pesadas, pacotes de aplicativos do lado do cliente e qualquer coisa que chame o backend quebrado. Um pequeno arquivo CSS é aceitável se o Nginx puder servi-lo diretamente.

Um 404.html mínimo poderia ser:

<!doctype html>
<html lang="pt">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Página não encontrada</title>
</head>
<body>
  <main>
    <h1>Página não encontrada</h1>
    <p>A página pode ter sido movida ou o link pode estar desatualizado.</p>
    <p><a href="/">Ir para a página inicial</a></p>
  </main>
</body>
</html>

Isso é suficiente. Você pode estilizá-lo para combinar com seu site, mas a mensagem e os links são mais importantes que a decoração.

Conecte as páginas com error_page

No Nginx, a diretiva error_page mapeia um ou mais códigos de status para uma URI. Um bloco de servidor básico se parece com isso:

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

    root /var/www/example.com/public;

    error_page 404 /errors/404.html;
    error_page 403 /errors/403.html;
    error_page 500 502 503 504 /errors/50x.html;

    location /errors/ {
        internal;
        root /var/www/example.com;
    }

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

A resolução do caminho é a parte que confunde as pessoas. Neste exemplo, as solicitações em /errors/ usam root /var/www/example.com;, então /errors/404.html mapeia para /var/www/example.com/errors/404.html.

A diretiva internal significa que clientes externos não podem solicitar /errors/404.html diretamente como uma URL normal. O Nginx ainda pode servi-lo internamente ao lidar com um erro.

Após editar a configuração, teste e recarregue:

sudo nginx -t
sudo systemctl reload nginx

Em seguida, teste o comportamento:

curl -I http://example.com/pagina-definitivamente-ausente
curl -s http://example.com/pagina-definitivamente-ausente | head

O status ainda deve ser 404, mesmo que o corpo seja seu HTML amigável. Um erro comum é retornar acidentalmente 200 OK para uma página ausente, o que faz com que o monitoramento e os mecanismos de busca pensem que a URL ausente é uma página real.

Páginas personalizadas atrás de um proxy reverso

Se o Nginx atua como proxy para um aplicativo upstream, o aplicativo pode retornar suas próprias respostas de erro. Por padrão, as respostas proxy são geralmente passadas de volta ao cliente. Para fazer o Nginx interceptar respostas de erro upstream e usar suas regras error_page, habilite proxy_intercept_errors no contexto relevante.

location /app/ {
    proxy_pass http://app_backend;
    proxy_intercept_errors on;

    error_page 502 503 504 /errors/50x.html;
}

A documentação do Nginx descreve proxy_intercept_errors como aplicável a respostas proxy com códigos de status maiores ou iguais a 300, que podem então ser redirecionados para o Nginx para processamento error_page. Na prática, não ative isso em todos os lugares sem pensar.

Para páginas de navegador, interceptar 502 ou 503 geralmente é útil. Para APIs JSON, pode estar errado. Clientes de API geralmente esperam um corpo de erro JSON estruturado, não uma página HTML. Você pode precisar de locais separados:

location /api/ {
    proxy_pass http://api_backend;
    proxy_intercept_errors off;
}

location /dashboard/ {
    proxy_pass http://app_backend;
    proxy_intercept_errors on;
    error_page 502 503 504 /errors/50x.html;
}

Essa divisão mantém as páginas voltadas para humanos amigáveis, preservando erros de API legíveis por máquina.

Preserve o código de status correto

O Nginx permite alterar o código de resposta com error_page, mas faça isso apenas quando for intencional. Esta é uma sintaxe válida:

error_page 404 =200 /fallback.html;

Para a maioria dos sites, isso seria uma má ideia. Uma página ausente deve permanecer como 404. Mecanismos de busca, verificações de uptime, análises e usuários se beneficiam da verdade.

Existem casos legítimos para alterar códigos, como rotear certos erros para um local nomeado ou retornar uma página de manutenção com 503. Mas, como regra padrão, preserve o status de erro original.

Para manutenção, você pode ser explícito:

location / {
    return 503;
}

error_page 503 /errors/maintenance.html;

location = /errors/maintenance.html {
    root /var/www/example.com;
    internal;
}

Se você usar um CDN ou balanceador de carga na frente do Nginx, lembre-se de que ele pode ter seu próprio comportamento de página de erro. Decida qual camada é responsável por quais erros. Caso contrário, você pode testar o Nginx diretamente e ver uma página, enquanto os usuários atrás do CDN veem outra.

Escreva páginas de erro para humanos

O conteúdo deve responder rapidamente a três perguntas:

  • O que aconteceu?
  • É temporário?
  • O que posso fazer a seguir?

Para um 404, os próximos passos úteis são pesquisa, página inicial, índice de documentação ou contatar o suporte se a página ausente deveria existir. Para um 503, a orientação útil é tentar novamente mais tarde ou verificar uma página de status. Para um 403, aponte para instruções de login ou solicitação de acesso, se apropriado.

Evite stack traces, nomes de host upstream, caminhos de sistema de arquivos, versões de pacotes, IPs internos, IDs de solicitação sem explicação e detalhes de incidentes. Um ID de solicitação pode ser útil se o suporte puder usá-lo, mas rotule-o claramente:

<p>Se você entrar em contato com o suporte, inclua este ID de solicitação: <code>$request_id</code></p>

Para injetar variáveis como $request_id, você precisa de um padrão de configuração que suporte isso. Arquivos HTML estáticos não expandirão variáveis do Nginx por si só. Muitas equipes mantêm páginas de erro públicas estáticas e dependem de logs para IDs de solicitação.

Acessibilidade faz parte da utilidade. Use um h1 claro, contraste legível, links normais e texto simples. Não torne a única ação de recuperação um pequeno ícone ou um botão acionado por script.

Teste as páginas propositalmente

Não espere os usuários encontrarem suas páginas de erro. Teste-as após cada alteração.

Para 404:

curl -i https://example.com/pagina-inexistente

Para 403, crie um local de teste controlado ou use um arquivo de teste privado. Não afrouxe as permissões de produção apenas para acionar um erro.

Para 502 ou 503, teste em staging apontando um local para um upstream indisponível:

location /broken-upstream-test/ {
    proxy_pass http://127.0.0.1:59999;
    proxy_intercept_errors on;
    error_page 502 503 504 /errors/50x.html;
}

Em seguida, solicite e confirme tanto o código de status quanto o corpo:

curl -i https://staging.example.com/broken-upstream-test/

Também observe os logs:

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

Uma página de erro de boa aparência não deve apagar o sinal operacional. Seus alertas ainda devem disparar quando as taxas de 50x aumentarem.

Páginas de erro personalizadas no Nginx são uma pequena tarefa de configuração com um impacto real no usuário. Comece com 404, 403 e os erros 50x comuns. Sirva arquivos estáticos diretamente do Nginx. Preserve códigos de status precisos. Use proxy_intercept_errors apenas onde fallbacks HTML fazem sentido. Em seguida, teste as páginas da mesma forma que testa qualquer outro comportamento de produção.