O que é cache de proxy no Nginx (e quando usar)
Cache de proxy é quando o Nginx armazena respostas vindas de um upstream (sua API/aplicação) para reutilizá-las em requisições futuras. Isso reduz latência e carga no backend, principalmente em endpoints idempotentes (por exemplo, GET de leitura) e com respostas repetidas.
O cache de proxy do Nginx funciona como um “armazenamento” local (em disco e/ou memória de metadados) indexado por uma cache key. Quando chega uma requisição, o Nginx calcula a chave; se existir uma resposta válida associada, retorna do cache (HIT), caso contrário busca no upstream e pode armazenar (MISS).
Conceitos essenciais
- Cache key: identifica unicamente uma resposta cacheada. Se a key não considerar algo importante (ex.:
Authorization), você pode servir conteúdo errado para outro usuário. - Validade (TTL): por quanto tempo um item é considerado válido. Pode vir do upstream (headers) ou ser definido no Nginx (
proxy_cache_valid). - Bypass/skip: condições para não usar o cache (bypass: não consultar; skip/no-store: não armazenar).
- Condições para não cachear: respostas com cookies, com headers que proíbem cache, métodos não idempotentes, ou quando você decide explicitamente.
Passo a passo: configuração mínima de cache de proxy
1) Criar a área de cache com proxy_cache_path
Esta diretiva define onde o cache fica no disco, como ele é indexado e qual o nome da zona (metadados em memória) usada por proxy_cache.
proxy_cache_path /var/cache/nginx/api_cache levels=1:2 keys_zone=api_cache:20m max_size=2g inactive=30m use_temp_path=off;/var/cache/nginx/api_cache: diretório no disco (garanta permissões para o usuário do Nginx).levels=1:2: estrutura de subpastas para distribuir arquivos (evita milhões em um único diretório).keys_zone=api_cache:20m: nome da zona + memória para metadados (não é o tamanho do cache em disco).max_size=2g: limite aproximado do cache em disco.inactive=30m: remove itens não acessados por 30 minutos (mesmo que ainda “válidos”).use_temp_path=off: grava diretamente no diretório do cache (muitas vezes melhora I/O).
2) Aplicar o cache em um location de API idempotente
Exemplo de cache para um endpoint de leitura (GET /api/). A ideia é cachear apenas respostas bem-sucedidas e por um tempo curto, com possibilidade de bypass.
location /api/ { proxy_pass http://api_upstream; proxy_cache api_cache; proxy_cache_methods GET HEAD; proxy_cache_valid 200 1m; proxy_cache_valid 404 10s; proxy_cache_key $scheme$proxy_host$request_uri; add_header X-Cache-Status $upstream_cache_status always;}Pontos importantes:
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
proxy_cache api_cache;usa a zona definida emproxy_cache_path.proxy_cache_methods GET HEAD;reforça que só métodos idempotentes entram no cache.proxy_cache_validdefine TTL por status HTTP (ex.:200por 1 minuto).proxy_cache_keydefine a chave. Aqui usamos esquema + host do proxy + URI completa. Em APIs, muitas vezes você também precisa considerar query string (já está em$request_uri).X-Cache-Statusajuda a validarHIT/MISS/BYPASS/EXPIREDetc.
Cache key: como evitar servir conteúdo errado
A cache key precisa refletir tudo que altera a resposta. Erros comuns:
- Conteúdo por usuário: se a resposta muda por
Authorization(token) e você não inclui isso na key, um usuário pode receber dados de outro. Em geral, não cacheie endpoints autenticados por usuário, ou use uma estratégia explícita. - Variação por header: se o upstream varia por
Accept-Language,Acceptetc., você pode precisar incluir esses headers na key.
Exemplo (use com cuidado) incluindo idioma:
proxy_cache_key $scheme$proxy_host$request_uri$http_accept_language;Para endpoints com autenticação, uma prática segura é bypassar e não armazenar quando houver Authorization:
set $skip_cache 0; if ($http_authorization != "") { set $skip_cache 1; }Bypass vs. Skip (não usar vs. não armazenar)
No Nginx, normalmente você controla isso com:
proxy_cache_bypass: quando verdadeiro, o Nginx não consulta o cache e vai ao upstream.proxy_no_cache: quando verdadeiro, o Nginx não armazena a resposta no cache.
É comum usar a mesma condição para ambos, garantindo que requisições “sensíveis” não sejam servidas do cache e nem gravadas.
Exemplo prático: bypass por query string e por header
Você pode permitir um “modo debug” para forçar MISS, e também bypassar quando o cliente mandar Cache-Control: no-cache.
location /api/ { set $skip_cache 0; if ($arg_nocache = "1") { set $skip_cache 1; } if ($http_cache_control ~* "no-cache|no-store") { set $skip_cache 1; } if ($request_method !~ ^(GET|HEAD)$) { set $skip_cache 1; } if ($http_authorization != "") { set $skip_cache 1; } proxy_pass http://api_upstream; proxy_cache api_cache; proxy_cache_methods GET HEAD; proxy_cache_bypass $skip_cache; proxy_no_cache $skip_cache; proxy_cache_valid 200 1m; proxy_cache_valid 404 10s; proxy_cache_key $scheme$proxy_host$request_uri; add_header X-Cache-Status $upstream_cache_status always;}Observações:
- O bypass por método evita cachear
POST,PUT,PATCH,DELETE. - O bypass por
Authorizationé uma proteção comum para não misturar respostas autenticadas. - O bypass por
Cache-Controlrespeita a intenção do cliente (útil em debug e em alguns fluxos).
Condições comuns para não cachear (boas práticas)
1) Respostas com Set-Cookie
Em geral, respostas que setam cookie são específicas e não devem ser cacheadas. O Nginx pode evitar cache automaticamente em alguns casos, mas você pode ser explícito:
proxy_no_cache $upstream_http_set_cookie;Isso impede armazenar quando o upstream envia Set-Cookie. Se você também quiser evitar servir do cache quando houver cookie na requisição:
proxy_cache_bypass $http_cookie;2) Respeitar diretivas do upstream (ou sobrescrever)
O upstream pode enviar cabeçalhos que controlam cache, principalmente:
Cache-Control: ex.:max-age=60,no-cache,no-store,private.Expires: data/hora de expiração (mais antigo, mas ainda usado).
Por padrão, o Nginx tende a respeitar diretivas que proíbem cache (como no-store) e pode usar informações de validade quando presentes. Porém, em muitos cenários você quer definir TTL no Nginx com proxy_cache_valid para ter previsibilidade.
3) Sobrescrever regras do upstream (quando você tem certeza)
Se o upstream não envia headers de cache adequados, você pode impor TTL no Nginx com proxy_cache_valid. Se o upstream envia Cache-Control: no-cache mas você quer cachear mesmo assim (com muito cuidado), você pode ignorar headers específicos com proxy_ignore_headers.
location /api/ { proxy_pass http://api_upstream; proxy_cache api_cache; proxy_cache_valid 200 1m; proxy_ignore_headers Cache-Control Expires; add_header X-Cache-Status $upstream_cache_status always;}Use isso apenas quando você controla o comportamento e entende o risco de servir dados desatualizados.
Validade (TTL) com proxy_cache_valid e cenários típicos
proxy_cache_valid permite TTL por código de status. Exemplos úteis:
proxy_cache_valid 200 302 1m; proxy_cache_valid 404 10s; proxy_cache_valid any 5s;200/302: cache curto para respostas “boas”.404: cache bem curto para reduzir carga em recursos inexistentes (evita martelar o backend).any: fallback para outros status (use com cautela; muitas APIs não devem cachear500).
Testes práticos: validando MISS/HIT com X-Cache-Status
1) Garantir que o header aparece sempre
Use always para o header aparecer mesmo em respostas de erro:
add_header X-Cache-Status $upstream_cache_status always;Valores comuns:
MISS: não estava no cache, buscou no upstream e (se permitido) armazenou.HIT: veio do cache.BYPASS: bypass ativado, foi ao upstream.EXPIRED: item existia mas expirou; buscou novamente.STALE,UPDATING,REVALIDATED: podem aparecer em cenários avançados (stale/revalidação).
2) Testar com curl
Primeira requisição (tende a ser MISS):
curl -i http://localhost/api/productsSegunda requisição (tende a ser HIT dentro do TTL):
curl -i http://localhost/api/productsForçar bypass via query string:
curl -i "http://localhost/api/products?nocache=1"Forçar bypass via header do cliente:
curl -i -H "Cache-Control: no-cache" http://localhost/api/products3) Validar que não cacheia quando há Authorization
curl -i -H "Authorization: Bearer test" http://localhost/api/productsCom as regras de $skip_cache, o esperado é X-Cache-Status: BYPASS e nenhuma gravação no cache.
Checklist rápido de segurança e previsibilidade
- Cacheie apenas endpoints idempotentes (
GET/HEAD) e com resposta compartilhável. - Defina uma cache key que reflita variações relevantes (URI, query string e, se necessário, headers).
- Evite cache para conteúdo por usuário (especialmente com
Authorization), a menos que você tenha uma estratégia explícita. - Use
proxy_cache_validpara TTL previsível e ajuste por status. - Implemente bypass/skip para debug e para condições sensíveis (cookies, auth, métodos não idempotentes).
- Teste sempre com
X-Cache-Statuspara confirmarMISS/HIT/BYPASS.