Servindo Arquivos Estáticos com Nginx: Dicas de Otimização
Otimize a entrega de arquivos estáticos do Nginx com cabeçalhos de cache adequados, compressão Gzip, padrões seguros e dicas para proteger arquivos ocultos — para sites mais rápidos com menos dores de cabeça com ativos desatualizados.
Servindo Arquivos Estáticos com Nginx: Dicas de Otimização
Servir arquivos estáticos com Nginx é uma das formas mais comuns e eficientes de entregar imagens, CSS, JavaScript, downloads e ativos de frontend compilados. O Nginx é muito bom nessa tarefa, mas algumas escolhas de configuração podem fazer a diferença entre um site rápido e previsível e um que desperdiça largura de banda ou serve conteúdo desatualizado.
A otimização de arquivos estáticos trata principalmente de caminhos claros, cabeçalhos de cache corretos, compressão e padrões seguros. Você não precisa de uma configuração complicada para obter resultados sólidos, mas precisa que as regras de cache correspondam à forma como seus arquivos são nomeados e implantados.
Comece com um Local Claro para Arquivos Estáticos
A configuração mais simples para arquivos estáticos usa root e try_files:
server {
listen 80;
server_name exemplo.com;
root /var/www/exemplo.com/public;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Com esta configuração, uma requisição para /css/app.css mapeia para /var/www/exemplo.com/public/css/app.css. Se o arquivo não existir, o Nginx retorna 404.
Esse mapeamento direto é útil durante a depuração. Você pode pegar uma URL do navegador, transformá-la em um caminho no sistema de arquivos e verificar se o arquivo existe:
ls -l /var/www/exemplo.com/public/css/app.css
Se o arquivo existe mas o Nginx retorna 404, procure por um root diferente, um bloco location mais específico ou um arquivo de inclusão que sobrescreva o caminho.
Para uma aplicação de página única, você pode querer que rotas desconhecidas caiam no index.html:
location / {
try_files $uri $uri/ /index.html;
}
Isso é útil para roteadores de frontend, mas não use cegamente para todos os sites. Se ativos faltantes também retornarem index.html, depurar caminhos quebrados de JavaScript ou imagens pode se tornar confuso. Muitas equipes usam um local separado para ativos para que arquivos faltantes ainda retornem um 404 real.
Você também pode usar alias quando um caminho de URL deve mapear para um caminho diferente no sistema de arquivos:
location /assets/ {
alias /srv/ativos-compartilhados/;
}
Cuidado com as barras no final. Com alias, o caminho do location e o caminho do sistema de arquivos geralmente devem terminar com /. Uma incompatibilidade pode produzir caminhos de arquivo inesperados.
Um padrão seguro é:
location /downloads/ {
alias /srv/downloads/;
try_files $uri =404;
}
Aqui /downloads/manual.pdf mapeia para /srv/downloads/manual.pdf. Sem a disciplina da barra no final, é fácil construir acidentalmente caminhos que não existem ou expor um diretório que você não pretendia publicar.
Para uma análise mais aprofundada do comportamento de correspondência, veja Blocos de location no Nginx.
Adicione Cabeçalhos de Cache do Navegador
Arquivos estáticos são excelentes candidatos para cache do navegador. Se um usuário baixar app.css uma vez, o navegador não deve buscá-lo novamente a cada visualização de página, a menos que tenha mudado.
Para ativos versionados, use tempos de vida de cache longos:
location /assets/ {
root /var/www/exemplo.com/public;
expires 1y;
add_header Cache-Control "public, immutable";
}
Isso funciona melhor quando os nomes dos arquivos mudam durante a implantação, como app.8f3a91.css ou bundle.20260523.js. Se o nome do arquivo muda quando o conteúdo muda, os navegadores podem armazenar em cache o arquivo antigo com segurança por um longo tempo.
Para arquivos que mantêm o mesmo nome, use cache mais curto:
location = /index.html {
root /var/www/exemplo.com/public;
expires -1;
add_header Cache-Control "no-cache";
}
Esse padrão é comum para aplicações frontend. O arquivo HTML permanece fresco, enquanto arquivos CSS e JavaScript com hash são armazenados em cache agressivamente.
Um exemplo prático: sua aplicação React ou Vue gera ativos com hash em /assets/ e um index.html simples. Coloque /assets/ em cache por um ano, mas faça o index.html revalidar. Os usuários obtêm visitas repetidas rápidas, e novas implantações ainda carregam as referências de ativos mais recentes.
Após alterar as regras de cache, teste os cabeçalhos em vez de adivinhar:
curl -I https://exemplo.com/assets/app.8f3a91.css
curl -I https://exemplo.com/
Você quer que o ativo com hash mostre um valor Cache-Control de longa duração. Geralmente você quer que a página HTML revalide ou use um tempo de vida curto. Se ambos forem armazenados em cache por um ano, uma implantação pode deixar os usuários presos em um arquivo HTML antigo que aponta para JavaScript antigo.
Use Compressão para Ativos de Texto
Ativos de texto como CSS, JavaScript, SVG e JSON comprimem bem. Você pode habilitar Gzip no bloco http:
gzip on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_vary on;
gzip_types
text/css
application/javascript
application/json
image/svg+xml;
Não espere que o Gzip ajude muito com arquivos JPEG, PNG, WebP, MP4 ou zip. Esses formatos já estão comprimidos. Tentar comprimi-los novamente geralmente desperdiça CPU.
Para sites estáticos de alto tráfego, considere arquivos pré-comprimidos. Seu processo de build pode criar versões .gz de arquivos CSS e JavaScript grandes, e o Nginx pode servi-los quando o navegador suportar Gzip:
gzip_static on;
Isso reduz o trabalho de compressão em tempo de execução porque o Nginx lê o arquivo pré-comprimido do disco. É mais útil quando os ativos são compilados antecipadamente e não mudam entre requisições.
Compressão é apenas uma parte da entrega de ativos. O tamanho do arquivo ainda importa. Remova JavaScript não utilizado, otimize imagens durante seu processo de build e evite enviar arquivos grandes que os usuários não precisam.
Ao testar a compressão, inclua um cabeçalho Accept-Encoding:
curl -I -H 'Accept-Encoding: gzip' https://exemplo.com/assets/app.js
Procure por Content-Encoding: gzip e Vary: Accept-Encoding. O cabeçalho Vary é importante quando um CDN ou cache compartilhado está na frente do Nginx, porque respostas comprimidas e não comprimidas não devem ser misturadas.
Melhore a Entrega e Segurança de Arquivos
O Nginx pode servir arquivos estáticos de forma eficiente com as configurações padrão, mas alguns detalhes ajudam em produção.
Primeiro, desative listagens de diretório a menos que você precise explicitamente delas:
autoindex off;
Listagens de diretório podem revelar nomes de arquivos e estrutura que você não pretendia publicar.
Segundo, bloqueie o acesso a arquivos ocultos como .env, .git e outros dotfiles:
location ~ /\.(?!well-known) {
deny all;
}
A exceção para .well-known é comum porque validação de certificado e arquivos baseados em padrões podem usar esse diretório.
Terceiro, certifique-se de que as permissões dos seus arquivos estáticos permitam que o Nginx leia os arquivos, mas não deem ao servidor web acesso de escrita desnecessário. Uma configuração típica permite que ferramentas de implantação escrevam arquivos e permite que o usuário do worker do Nginx os leia.
Quarto, verifique os tipos MIME. O Nginx geralmente inclui um arquivo mime.types, mas contêineres reduzidos ou builds personalizados podem perdê-lo. Se CSS for servido como text/plain, os navegadores podem rejeitá-lo ou se comportar de forma diferente.
Use:
include /etc/nginx/mime.types;
default_type application/octet-stream;
Finalmente, monitore os logs em busca de respostas 404 repetidas em ativos. Isso geralmente significa que uma implantação referenciou arquivos que não existem, um cache ainda aponta para um nome de arquivo antigo ou um caminho alias está errado.
Se a entrega estática parecer lenta, não comece copiando todas as diretivas de ajuste que encontrar. Primeiro verifique se o problema é realmente o Nginx. Imagens grandes, bundles de frontend não otimizados, montagens de armazenamento remoto e erros de cache do CDN são causas mais comuns do que uma micro-otimização faltando no bloco do servidor.
Para uma verificação local rápida:
curl -o /dev/null -s -w 'status=%{http_code} size=%{size_download} time=%{time_total}\n' https://exemplo.com/assets/app.js
Depois compare isso com logs do CDN, ferramentas de desenvolvedor do navegador ou uma requisição da mesma região que seus usuários. Uma resposta rápida do Nginx e uma resposta lenta no navegador geralmente apontam para outro lugar no caminho de entrega.
Quando Buscar Ajuda
Traga um engenheiro DevOps se seus arquivos estáticos forem servidos de armazenamento compartilhado, volumes montados, gateways de armazenamento de objetos ou um CDN na frente do Nginx. A melhor estratégia de cache depende de todo o caminho de entrega, não apenas do bloco do servidor Nginx.
Você também deve buscar ajuda se os usuários relatarem JavaScript desatualizado após implantações. Isso geralmente significa que as regras de cache e a estratégia de versionamento de nomes de arquivo não correspondem.
Servir arquivos estáticos com Nginx funciona melhor quando os caminhos são previsíveis, os tempos de vida do cache correspondem à estratégia de nomes de arquivo e os ativos de texto são comprimidos. Mantenha arquivos faltantes visíveis, proteja arquivos ocultos e teste os cabeçalhos após cada mudança de configuração. Uma configuração estática limpa torna seu site mais rápido sem adicionar partes móveis.