Como corrigir o erro 404 no Angular ao efetuar o refresh ou acessar rotas diretamente do navegador
O erro 404 no Angular surge quando o servidor web não está configurado para lidar com o roteamento client-side do Angular. Aprenda a corrigir esse problema no Nginx e Apache

Se você trabalha com projetos que usam o framework Angular, talvez tenha enfrentado um problema comum: tudo funciona perfeitamente durante o desenvolvimento. No entanto, após implantar o projeto em produção, ao navegar entre as rotas, você percebe que, ao atualizar a página ou tentar acessar uma rota diretamente na barra de endereços, surge o erro 404 Not Found. Neste texto, vamos entender por que isso acontece e como resolver esse problema.
Servindo arquivos estáticos para web
Arquivos estáticos, como HTML, CSS, JavaScript e imagens, são a base de muitos sites e aplicações web, incluindo projetos Angular. Servi-los de forma eficiente é crucial para garantir uma experiência rápida, confiável e segura para os usuários.
Nesse contexto, softwares como Nginx, Apache e serviços de hospedagem estática como GitHub Pages se destacam por sua simplicidade, performance e escalabilidade. Ao invés de processar cada requisição dinamicamente, esses servidores entregam os arquivos estáticos diretamente aos usuários, reduzindo a carga do servidor e otimizando o tempo de resposta.
Para projetos Angular, essa abordagem é particularmente vantajosa, pois após compilarmos o projeto, o resultado é composto por arquivos estáticos (html, js, css e imagens).

Dito isso, vamos criar um cenário de estudo envolvendo um projeto Angular com algumas rotas. Em seguida, vamos servir os arquivos através do Nginx e Apache para explorar a causa do erro 404 Not Found. Por fim, faremos um ajuste para resolver esse problema.
Cenário de estudo: criando o projeto Angular
Parar criar o projeto Angular:
# Conferindo a versão do Angular/CLI
> ng version
Angular CLI: 18.1.1
Node: 20.12.0
Package Manager: npm 10.8.1
OS: darwin arm64
# Criando o projeto
> ng new \
--skip-git \
--skip-tests \
--standalone \
--strict \
--minimal \
--inline-template \
--routing \
exemplo404
ng new help
para visualizar os parâmetros do comando ng new
Adicionando rotas ao projeto
Com o projeto criado, vamos adicionar 2 componentes, um para cada rota:
# Criando os componentes:
#
# Certifique-se de estar no diretório do projeto.
# Use o comando pwd para verificar seu diretório atual.
#
> ng g c rota1 --skip-tests --style none
> ng g c rota2 --skip-tests --style none
Mapeando as rotas:
import { Routes } from "@angular/router";
import { Rota1Component } from "./rota1/rota1.component";
import { Rota2Component } from "./rota2/rota2.component";
export const routes: Routes = [
{
path: "",
component: Rota1Component,
},
{
path: "rota2",
component: Rota2Component,
},
];
app.routes.ts
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';
@Component({
standalone: true,
imports: [RouterModule],
template: `
<p>
rota1 works!
</p>
<button [routerLink]="['/rota2']">
ir para rota 2
</button>
`,
styles: ``
})
export class Rota1Component {
}
rota1.component.ts
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';
@Component({
standalone: true,
imports: [RouterModule],
template: `
<p>
rota2 works!
</p>
<button [routerLink]="['/']">
ir para rota 1
</button>
`,
styles: ``
})
export class Rota2Component {
}
rota2.component.ts
Efetuando um teste em modo de desenvolvimento
Com o projeto configurado, vamos testá-lo em modo de desenvolvimento executando o comando npm run start
:

Veja no GIF acima que podemos mudar a rota diretamente na barra de endereços do navegador e atualizar a página sem problemas. Tudo funciona perfeitamente no modo de desenvolvimento.
Compilando o projeto
Visto que o projeto está funcionando corretamente, vamos efetuar o build do projeto com o comando npm run build
. Após o processamento, o resultado do build estará no diretório /dist/exemplo404/browser deste exemplo.

Testando o projeto sendo servido pelo Nginx
Para simular o erro 404, vamos servir os arquivos gerados anteriormente usando o Nginx.
Para evitar a instalação do Nginx no meu computador, usei um container Docker. Utilizei o comando abaixo para criar um container Docker a partir de uma imagem do Nginx:
> docker run \
--name nginx-angular \
-v /<dir do projeto>/dist/exemplo404/browser:/usr/share/nginx/html:ro \
-p 8080:80 \
-d nginx
Explicação do comando:
- --name
Nome do container - -v
Vincula um diretório do meu computador (host) com um diretório dentro do container. - -p:
Vincula uma porta no meu computador (host) com uma porta do container. - -d:
Nome da imagem
Erro 404 Not Found
Após executar o comando acima, o container do Nginx estará em execução, então podemos abrir o navegador e acessar o endereço http://localhost:8080
para carregar a aplicação Angular.
Nexte contexto, se acessarmos localhost:8080/favicon.ico
ou localhost:8080/main-XZS6USHQ.js
, o Nginx retornará o conteúdo desses arquivos corretamente. No entanto, se tentarmos acessar localhost:8080/rota2
, o Nginx devolverá o erro 404 Not Found. Isso ocorre porque o Nginx não sabe como lidar com essa rota. Ele tenta encontrar um arquivo ou diretório chamado rota2
e, como não existe, retorna o erro 404.
Observação: Lembre-se de que configuramos o Nginx para usar o diretório com os arquivos do projeto de exemplo (veja a imagem abaixo). Esses são os arquivos estáticos que o Nginx pode servir:

Por outro lado, se você acessar localhost:8080
ou localhost:8080/index.html
, o Nginx retornará o conteúdo do arquivo index.html
, que é o ponto de entrada da aplicação Angular. Uma vez que a aplicação Angular é carregada e interpretada pelo navegador, ela gerencia as rotas internamente. Isso significa que você pode navegar entre as rotas usando links ou botões dentro da própria aplicação.
Veja no GIF abaixo que a navegação pelos botões funciona perfeitamente. Porém, se usarmos a barra de endereços do navegador ou atualizarmos a página em uma rota diferente da raiz, aparece o erro 404.

Resolvendo o erro 404 Not Found no Nginx
Para resolver isso, é necessário configurar o Nginx para sempre servir o arquivo index.html
para qualquer rota desconhecida. Desta forma, quando o navegador carregar o index.html
, o contexto do Angular será criado, permitindo que o Angular gerencie as rotas após o carregamento inicial.
No caso do Nginx, existe um arquivo de configuração chamado nginx.conf
onde podemos configurar esse comportamento. Para obter o conteúdo desse arquivo podemos executar os seguintes comandos:
# Acessando o terminal do container
> docker exec -it nginx-angular /bin/bash
# Obtendo o conteúdo do arquivo:
> cat /etc/nginx/nginx.conf
Com o conteúdo do arquivo nginx.conf
em mãos, criei um arquivo com o mesmo nome dentro do diretório do projeto Angular (o local é opcional) e fiz a seguinte modificação:
user nginx;
worker_processes auto;
# (linhas ocultadas...)
http {
# (linhas ocultadas...)
# Comentei a linha abaixo e substituí
# pelo conteúdo a seguir
# include /etc/nginx/conf.d/*.conf;
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
# Quando o arquivo não for encontrado,
# irá devolver o index.html
try_files $uri $uri/ /index.html;
}
# (linhas ocultadas...)
}
}
nginx.conf
Finalmente removi o container que está em execução e recriei incluindo a configuração do Nginx customizada logo acima:
# Interrompendo a execução do container
> docker container stop nginx-angular
# Removendo o container
> docker container rm nginx-angular
# Criando um novo container
> docker run \
--name nginx-angular \
-v /<dir do projeto>/dist/exemplo404/browser:/usr/share/nginx/html:ro \
-v /<dir do projeto>/nginx.conf:/etc/nginx/nginx.conf:ro \
-p 8080:80 \
-d nginx
Resultado:


Testando o projeto sendo servido pelo Apache
De forma similar ao Nginx, mas agora com o Apache, segui as seguintes etapas:
Criando o container Docker do Apache
Primeiramente criei um container com a imagem do Apache com o comando abaixo:
docker run \
--name apache-angular \
-p 9090:80 \
-v /<dir do projeto>/dist/exemplo404/browser:/usr/local/apache2/htdocs:ro \
-d httpd:2.4
Obtendo o arquivo httpd.conf
Assim como no Nginx, neste momento o container em execução apresenta o mesmo problema do 404. Então de forma similar ao Nginx, precisamos obter o conteúdo do arquivo de configuração do Apache para aplicar uma modificação. Para isto acessei o terminal do container com os seguintes comandos:
> docker exec -it "apache-angular" /bin/bash
# A partir daqui estamos no console
# do container
#
# Obtendo o conteúdo do arquivo httpd.conf:
#
> cat /usr/local/apache2/conf/httpd.conf
Modificando o arquivo de configuração httpd.conf
Então criei um arquivo chamado httpd.conf
no diretório do meu projeto com as seguintes modificações:
ServerRoot "/usr/local/apache2"
Listen 80
# ...(linhas ocultadas)
LoadModule rewrite_module modules/mod_rewrite.so
# ...(linhas ocultadas)
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
# ...(linhas ocultadas)
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
</Directory>
# ...(linhas ocultadas)
httpd.conf
Recriando o container
Para finalizar executei os comandos abaixo:
# Para a execução do container
> docker container stop "apache-angular"
# Remove o container
> docker container rm "apache-angular"
# Cria o container
> docker run \
--name apache-angular \
-p 9090:80 \
-v /<dir do projeto>/dist/exemplo404/browser:/usr/local/apache2/htdocs:ro \
-v /<dir do projeto>/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro \
-d httpd:2.4
Resultado:

Considerações
Neste texto, falamos sobre o erro 404 que surge ao atualizar ou acessar rotas client-side diretamente no navegador em aplicações Angular. Abordamos as soluções envolvendo o Nginx e Apache, configurando para entregar o arquivo principal da aplicação (index.html
) quando uma rota não for encontrada.
Outros frameworks ou bibliotecas como React, seguem o mesmo princípio do Angular no roteamento client-side. Então ao configurar o servidor de arquivos estáticos para entregar o index.html
quando uma rota não for encontrada, a aplicação poderá assumir o controle do roteamento e exibir o conteúdo correto.