O que é compressão HTTP e por que ela importa
Compressão HTTP é o processo de reduzir o tamanho do corpo (body) de uma resposta antes de enviá-la ao cliente. Em vez de transferir o conteúdo “cru”, o servidor envia uma versão comprimida e indica isso via header Content-Encoding (por exemplo, gzip ou br). O navegador (ou cliente HTTP) descomprime automaticamente ao receber.
O objetivo é diminuir bytes transferidos e, muitas vezes, melhorar o tempo de carregamento percebido, especialmente em conexões lentas ou com alta latência. O custo é CPU no servidor (para comprimir) e no cliente (para descomprimir), além de alguns cuidados de compatibilidade e cache.
Quando compressão ajuda (e quando pode atrapalhar)
Ajuda principalmente em conteúdo textual
Conteúdos textuais têm muita redundância e costumam comprimir muito bem. Exemplos típicos:
text/html,text/css,application/javascriptapplication/json,application/xml,image/svg+xml- Fontes em formato texto (menos comum hoje), manifests, etc.
Em páginas e APIs, a redução pode ser grande (às vezes 60–90%), o que reduz tempo de download e custo de banda.
Pode atrapalhar em conteúdo binário já comprimido
Muitos formatos binários já são comprimidos internamente. Tentar comprimir de novo costuma trazer ganho mínimo e pode piorar:
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
- Imagens:
jpg,png,webp,avif - Vídeos:
mp4,webm - Arquivos compactados:
zip,gz,rar,7z - PDF (frequentemente já comprimido)
Nesses casos, você gasta CPU para quase nenhum benefício e pode aumentar latência sob carga. Por isso, a configuração segura foca em tipos textuais.
CPU, latência e tamanho de resposta
- Respostas pequenas: o ganho pode ser irrelevante; o overhead de compressão pode não compensar.
- Respostas grandes: o ganho tende a ser significativo, mas o custo de CPU também aumenta.
- Servidores com CPU limitada: compressão agressiva pode virar gargalo.
Compressão e cache: por que o header Vary importa
Clientes enviam Accept-Encoding para dizer quais compressões suportam (ex.: gzip, br). Se você usa cache (CDN, proxy, cache intermediário), é importante que ele diferencie versões comprimidas e não comprimidas. Para isso, a resposta deve incluir:
Vary: Accept-Encoding
Sem isso, um cache pode servir uma resposta gzip para um cliente que não pediu gzip (ou o contrário), causando comportamento incorreto.
Cuidado com “double-compression” (compressão dupla)
Compressão dupla acontece quando o upstream (aplicação) já envia conteúdo comprimido e o Nginx tenta comprimir novamente, ou quando você serve arquivos já comprimidos (ex.: .gz) e ainda habilita gzip indiscriminadamente. Isso pode gerar:
- Respostas inválidas (cliente não consegue descomprimir corretamente)
- CPU desperdiçada
- Headers incoerentes (ex.:
Content-Encodingduplicado)
Uma configuração segura evita comprimir tipos que já são comprimidos e, em cenários de proxy, garante que o Nginx não tente recomprimir algo que já veio com Content-Encoding.
Habilitando gzip de forma segura (passo a passo)
1) Ative gzip e defina um conjunto seguro de tipos
O gzip no Nginx é controlado por diretivas no contexto http, server ou location. Em geral, faz sentido configurar no http para valer globalmente, ajustando exceções quando necessário.
gzip on; gzip_types text/plain text/css application/javascript application/json application/xml image/svg+xml; gzip_min_length 1024; gzip_comp_level 5; gzip_vary on; gzip_proxied any;O que cada parte faz:
gzip on;: habilita compressão gzip.gzip_types ...;: lista de MIME types que serão comprimidos. Foque em texto. Evite imagens/vídeos/arquivos compactados.gzip_min_length 1024;: só comprime respostas acima de 1 KB (ajuste conforme seu cenário). Ajuda a evitar overhead em respostas pequenas.gzip_comp_level 5;: nível de compressão (1–9). Valores médios (4–6) costumam equilibrar bem CPU vs redução. Níveis altos aumentam CPU para ganhos marginais.gzip_vary on;: adicionaVary: Accept-Encoding.gzip_proxied any;: permite gzip mesmo quando há proxies no caminho (útil em reverse proxy). Em ambientes mais restritivos, você pode limitar (ex.:expired,no-cache, etc.).
2) Garanta que o tipo correto está sendo detectado
O Nginx decide o Content-Type com base em mapeamento de extensões para MIME types. Se o tipo estiver errado, o gzip pode não ser aplicado (ou pode ser aplicado indevidamente). Em configurações padrão, isso vem do arquivo de tipos MIME incluído. Se você notar que .js ou .json não estão sendo comprimidos, verifique se o Content-Type está correto na resposta.
3) Evite comprimir conteúdo já comprimido
Uma regra prática segura é: não inclua tipos binários comuns em gzip_types. Se você serve downloads (ex.: .zip), não os inclua. Se você tem endpoints que já retornam gzip (por exemplo, a aplicação já comprime), o Nginx normalmente não recomprime se a resposta já vier com Content-Encoding, mas é importante não forçar comportamentos estranhos com regras agressivas.
4) (Opcional) gzip_static para arquivos pré-comprimidos
Se você gera arquivos estáticos pré-comprimidos (por exemplo, app.js.gz ao lado de app.js), o Nginx pode servir diretamente a versão .gz quando o cliente aceita gzip. Isso economiza CPU porque não comprime em tempo real.
gzip_static on;Observações:
- Requer que você mantenha os arquivos
.gzatualizados junto dos originais. - Não é obrigatório para ter gzip; é uma otimização.
5) Verifique se não está comprimindo duas vezes via pipeline
Em cenários com CDN ou proxy na frente, pode haver compressão em mais de um ponto. O ideal é escolher onde comprimir (CDN ou Nginx) e manter consistente. Se a CDN já comprime, você pode desabilitar gzip no Nginx para reduzir CPU, ou manter gzip no Nginx e configurar a CDN para respeitar o origin sem recomprimir (depende do provedor).
Brotli (br): visão conceitual e uso recomendado
O que é brotli e por que ele existe
Brotli é um algoritmo de compressão moderno (header Content-Encoding: br) que costuma oferecer melhor taxa de compressão que gzip para conteúdo textual, frequentemente com tamanhos menores. Em geral:
- Melhor compressão: reduz mais bytes em HTML/CSS/JS/JSON.
- Custo de CPU: pode ser maior para comprimir, especialmente em níveis altos.
- Descompressão: geralmente eficiente em navegadores modernos.
Compatibilidade e negociação
Clientes informam suporte via Accept-Encoding. Navegadores modernos suportam br amplamente, mas alguns clientes antigos ou ferramentas podem não suportar. Por isso, o ideal é oferecer brotli quando o cliente pede e manter gzip como fallback.
Dependências e como pensar a adoção (sem instalação avançada)
Ao contrário do gzip (que vem nativamente no Nginx), brotli normalmente depende de um módulo adicional (varia por distribuição/pacote). Conceitualmente, você tem três cenários:
- Nginx com módulo brotli disponível: você habilita
brotli on;e definebrotli_typessemelhantes aos do gzip. - Sem módulo brotli: mantenha gzip bem configurado; já resolve a maior parte dos ganhos.
- Arquivos pré-comprimidos: algumas pipelines geram
.bre.gzpara assets estáticos; o servidor escolhe conformeAccept-Encoding.
Uma estratégia segura e comum é: habilitar brotli para assets estáticos (CSS/JS) e manter gzip como fallback, evitando níveis extremos de brotli em compressão on-the-fly se a CPU for uma preocupação.
Exemplo conceitual de configuração (se o módulo existir)
Os nomes das diretivas podem variar conforme o módulo, mas a ideia é:
brotli on; brotli_comp_level 5; brotli_types text/plain text/css application/javascript application/json application/xml image/svg+xml;Boas práticas:
- Use níveis médios (por exemplo 4–6) para equilibrar CPU.
- Não comprima binários já comprimidos.
- Mantenha gzip habilitado para compatibilidade.
Laboratório: verificar Content-Encoding e comparar tamanho transferido com curl
Objetivo
- Confirmar se o servidor está enviando
Content-Encoding: gzip(oubr). - Comparar o tamanho transferido com e sem compressão.
Preparação
Escolha uma URL que retorne conteúdo textual e com tamanho razoável (por exemplo, um arquivo .css, .js ou uma resposta JSON). Nos exemplos abaixo, substitua https://seu-dominio.exemplo/arquivo.js pela sua URL.
1) Ver headers sem pedir compressão
Envie uma requisição indicando que você não aceita compressão (ou aceitando apenas identity):
curl -sI -H 'Accept-Encoding: identity' https://seu-dominio.exemplo/arquivo.jsProcure por:
Content-Encoding: idealmente ausente (ou não gzip/br)Content-Length: tamanho do corpo sem compressão (quando presente)Vary: Accept-Encoding: recomendado quando há compressão habilitada
2) Ver headers pedindo gzip
curl -sI -H 'Accept-Encoding: gzip' https://seu-dominio.exemplo/arquivo.jsVocê deve ver:
Content-Encoding: gzipVary: Accept-EncodingContent-Lengthmenor (nem sempre aparece, dependendo de chunked/HTTP2)
3) (Opcional) Ver headers pedindo brotli
Se você tiver brotli habilitado e o cliente suportar, teste:
curl -sI -H 'Accept-Encoding: br' https://seu-dominio.exemplo/arquivo.jsProcure por Content-Encoding: br. Se não aparecer, pode ser que o módulo não esteja ativo, que o tipo não esteja em brotli_types ou que haja algum intermediário alterando a resposta.
4) Comparar tamanho transferido (bytes baixados) com e sem compressão
Para comparar o tamanho efetivamente transferido na rede, use curl com saída descartada e estatísticas de tamanho. O campo size_download representa bytes baixados do corpo (já comprimido, se houver compressão).
Sem compressão:
curl -s -o /dev/null -H 'Accept-Encoding: identity' -w 'download_bytes=%{size_download}\n' https://seu-dominio.exemplo/arquivo.jsCom gzip:
curl -s -o /dev/null -H 'Accept-Encoding: gzip' -w 'download_bytes=%{size_download}\n' https://seu-dominio.exemplo/arquivo.jsSe brotli estiver disponível:
curl -s -o /dev/null -H 'Accept-Encoding: br' -w 'download_bytes=%{size_download}\n' https://seu-dominio.exemplo/arquivo.jsInterpretação:
- Se
download_bytescom gzip/br for significativamente menor, a compressão está funcionando e trazendo ganho. - Se a diferença for pequena, o conteúdo pode ser pequeno, pouco compressível, ou já estar otimizado/minificado.
5) Validar que não há compressão dupla
Faça uma checagem simples: quando você pede gzip, deve haver no máximo um Content-Encoding (por exemplo, apenas gzip). Verifique:
curl -sI -H 'Accept-Encoding: gzip' https://seu-dominio.exemplo/arquivo.js | grep -i 'content-encoding'Se você observar algo inesperado (por exemplo, múltiplos encodings ou comportamento inconsistente entre requisições), revise:
- Se o upstream já está comprimindo respostas
- Se há CDN/proxy recomprimindo
- Se você está servindo arquivos pré-comprimidos e também aplicando compressão dinâmica de forma indevida