Locations no Nginx: correspondência, precedência e boas práticas

Capítulo 6

Tempo estimado de leitura: 8 minutos

+ Exercício

O que é um location e por que a correspondência importa

Dentro de um server, o Nginx usa blocos location para decidir como tratar uma requisição com base no caminho da URL (a parte após o domínio e porta, como /, /static/app.css, /api/users). Um mesmo server pode ter vários location, e a escolha do bloco correto segue regras de correspondência e precedência. Entender essas regras evita comportamentos inesperados, como uma rota de API sendo tratada como arquivo estático, ou um caminho sensível ficando exposto.

Tipos de correspondência: =, prefixo, ^~ e regex

O Nginx compara o caminho da requisição com os location disponíveis. Existem quatro formas principais:

  • Exata (=): casa somente se o caminho for exatamente igual.
  • Prefixo (sem modificador): casa se o caminho começar com o prefixo. Ex.: location /api/ casa com /api/users.
  • Prefixo com prioridade (^~): se casar, o Nginx para de procurar regex e usa esse bloco (útil para evitar que uma regex “roube” caminhos).
  • Regex (~ e ~*): casa por expressão regular. ~ é sensível a maiúsculas/minúsculas; ~* é case-insensitive.

Ordem de decisão (modelo mental prático)

Use este roteiro para prever qual location será escolhido:

  1. Se existir um location = /caminho que case exatamente, ele vence imediatamente.
  2. O Nginx encontra o melhor location por prefixo (o mais longo que casar). Se esse melhor prefixo tiver ^~, ele vence e a busca termina.
  3. Se não houve ^~ vencedor, o Nginx testa os location regex (~/~*) na ordem em que aparecem no arquivo. O primeiro regex que casar vence.
  4. Se nenhum regex casar, vence o melhor prefixo encontrado no passo 2.

Dois detalhes importantes: regex é testado depois de achar o melhor prefixo, mas pode substituir o prefixo (a menos que o prefixo seja ^~). E entre regex, a ordem no arquivo importa.

Exemplos claros de precedência

Exemplo 1: = vencendo tudo

server {    location = / {        return 200 "HOME exata";    }    location / {        return 200 "HOME por prefixo";    }}

Requisição / retorna “HOME exata”. Requisição /qualquer retorna “HOME por prefixo”.

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

Exemplo 2: prefixo longo vence prefixo curto

server {    location /api/ {        return 200 "API";    }    location / {        return 200 "RAIZ";    }}

/api/users casa com /api/ (prefixo mais longo) e retorna “API”. /contato cai em /.

Exemplo 3: regex “roubando” de um prefixo (sem ^~)

server {    location /static/ {        return 200 "STATIC por prefixo";    }    location ~* \.(css|js|png|jpg)$ {        return 200 "ASSET por regex";    }}

/static/app.css primeiro encontra melhor prefixo (/static/), mas como não é ^~, o Nginx testa regex e a regex casa, então vence “ASSET por regex”. Isso pode ser desejado (um tratamento único para extensões) ou um problema (você queria regras específicas para /static/).

Exemplo 4: usando ^~ para proteger um prefixo contra regex

server {    location ^~ /static/ {        return 200 "STATIC fixo";    }    location ~* \.(css|js|png|jpg)$ {        return 200 "ASSET por regex";    }}

Agora /static/app.css retorna “STATIC fixo”, porque ^~ impede que regex seja considerado após o match do prefixo.

Passo a passo prático: montar um laboratório de testes de location

A forma mais rápida de aprender precedência é criar um server de teste que responde com mensagens diferentes. Assim você confirma qual location foi acionado sem depender de logs complexos.

1) Criar um conjunto de location com respostas explícitas

server {    listen 8080;    server_name _;    location = / {        return 200 "MATCH: = /";    }    location / {        return 200 "MATCH: prefix /";    }    location /api/ {        return 200 "MATCH: prefix /api/";    }    location ^~ /static/ {        return 200 "MATCH: ^~ /static/";    }    location ~ ^/api/v[0-9]+/ {        return 200 "MATCH: regex ^/api/vN/";    }    location ~* \.(css|js|png|jpg)$ {        return 200 "MATCH: regex ext";    }}

2) Testar com requisições e observar o corpo da resposta

Exemplos de testes (substitua o host conforme necessário):

curl -i http://localhost:8080/ curl -i http://localhost:8080/qualquer curl -i http://localhost:8080/api/users curl -i http://localhost:8080/api/v1/users curl -i http://localhost:8080/static/app.css curl -i http://localhost:8080/images/logo.png

Interpretação esperada:

  • / deve cair em = /.
  • /qualquer deve cair em prefix /.
  • /api/users deve cair em prefix /api/ (a regex ^/api/vN/ não casa).
  • /api/v1/users deve cair em regex ^/api/vN/ (porque não há ^~ em /api/ e a regex casa).
  • /static/app.css deve cair em ^~ /static/ (mesmo que a regex de extensão também casasse).
  • /images/logo.png deve cair em regex ext (não há prefixo específico além de /).

Padrões comuns de organização: /, /static/, /api/

Raiz /: o “fallback” previsível

O location / normalmente funciona como rota padrão para tudo que não casar em algo mais específico. Boas práticas:

  • Mantenha location / mais “genérico” possível.
  • Evite colocar regras muito específicas no /, pois elas podem afetar caminhos inesperados.
location / {    return 200 "fallback";}

/static/: separar assets e evitar conflitos com regex

Quando você tem um diretório dedicado para arquivos estáticos, é comum querer que tudo sob /static/ siga um comportamento consistente. Se você também usa regex para extensões, considere ^~ para impedir que a regex intercepte caminhos de /static/.

location ^~ /static/ {    # regras específicas para /static/ (cache, headers, etc.)    # aqui usamos return apenas para demonstrar o match    return 200 "static";}

Se você quiser que uma regex de extensão aplique também dentro de /static/, então não use ^~ e organize a regex com cuidado (e teste).

/api/: rotas de aplicação e regex de versionamento

APIs frequentemente têm padrões como /api/ e versões (/api/v1/, /api/v2/). Use prefixos para separar a API do restante e regex apenas quando necessário.

location /api/ {    return 200 "api";}location ~ ^/api/v[0-9]+/ {    return 200 "api versionada";}

Se você quer que /api/ sempre vença e nenhuma regex de “atalho” interfira, use ^~:

location ^~ /api/ {    return 200 "api sempre por prefixo";}location ~ ^/api/v[0-9]+/ {    return 200 "nunca será usado";}

Isso é útil quando regex foi criada para outro propósito e acabou casando com caminhos da API.

Controle de acesso e negação para caminhos sensíveis

Alguns caminhos não devem ser acessíveis publicamente, como arquivos ocultos, diretórios internos, endpoints administrativos ou dumps. O Nginx permite negar acesso por prefixo ou regex.

Negar por prefixo (mais simples e previsível)

location ^~ /admin/ {    deny all;}

Com ^~, você reduz o risco de uma regex posterior “capturar” /admin/ e aplicar outra regra.

Negar arquivos ocultos (ex.: .env, .git) com regex

location ~ /\. {    deny all;}

Esse padrão bloqueia qualquer caminho que contenha um segmento iniciado por ponto (como /.git/config ou /.env). Teste cuidadosamente se você tem URLs legítimas com ponto no caminho.

Negar extensões sensíveis (ex.: backups)

location ~* \.(bak|old|sql|zip|tar|gz)$ {    deny all;}

Como regex é avaliado por ordem, mantenha regras de negação em posição adequada para não serem “sombras” por outras regex mais genéricas.

Boas práticas para evitar conflitos e surpresas

1) Prefira prefixos para estrutura de rotas

Use location /api/, location /static/, location /health etc. Regex é poderosa, mas aumenta a chance de colisões e depende da ordem no arquivo.

2) Use = para caminhos únicos e críticos

Exemplos: /, /robots.txt, /favicon.ico, /health. Isso evita que um prefixo ou regex altere o comportamento.

location = /health {    return 200 "ok";}

3) Use ^~ para “zonas” que não devem sofrer regex

Exemplos típicos: /static/, /uploads/, /admin/, /api/ (dependendo do desenho). Isso torna o roteamento mais previsível.

4) Cuidado com regex genéricas de extensão

Regex como ~* \.(css|js|png|jpg)$ podem casar em muitos lugares (inclusive dentro de /api/ se houver caminhos com ponto). Se você precisa dessa regex, avalie:

  • Restringir o escopo: location ~* ^/static/.*\.(css|js|png|jpg)$
  • Ou proteger prefixos com ^~

5) Ordene regex do mais específico para o mais genérico

Como o primeiro regex que casa vence, coloque regras específicas antes das genéricas.

location ~ ^/api/v[0-9]+/admin/ { deny all; }location ~ ^/api/v[0-9]+/ { return 200 "api vN"; }location ~* \.(css|js|png|jpg)$ { return 200 "assets"; }

Exercícios de depuração: descobrir qual location está sendo acionado

Exercício 1: prever o match (sem rodar)

Dado o conjunto abaixo, diga qual location atende cada URL:

location / { return 200 "A"; }location /api/ { return 200 "B"; }location ~ ^/api/v[0-9]+/ { return 200 "C"; }location ^~ /static/ { return 200 "D"; }location ~* \.(png|jpg)$ { return 200 "E"; }
  • /api/v1/users
  • /api/users
  • /static/logo.jpg
  • /images/logo.jpg

Depois, confirme com curl usando o laboratório de respostas por return.

Exercício 2: um conflito comum entre /static/ e regex de extensão

Você quer que tudo em /static/ use regras próprias, mas percebe que /static/app.js está caindo na regex de extensão. Ajuste a configuração para que /static/ sempre vença.

Dica: compare o comportamento com e sem ^~ e teste:

curl -i http://localhost:8080/static/app.js

Exercício 3: bloquear um caminho sensível sem quebrar o resto

Você precisa bloquear /.git/ e /.env, mas manter acessível /static/.well-known/ (se existir esse uso no seu cenário). Proponha uma regra que bloqueie arquivos ocultos e, se necessário, uma exceção mais específica.

Estratégia de teste: crie respostas diferentes para “bloqueado” e “permitido” e verifique com curl -i quais caminhos caem em cada regra.

Exercício 4: tornar o roteamento previsível em uma API versionada

Você quer que /api/ seja sempre tratado como API (nunca como asset por regex de extensão), e que /api/v1/ tenha regras específicas. Ajuste os location para:

  • /api/v1/... cair em uma regra dedicada
  • qualquer /api/... cair em uma regra geral
  • nenhuma regex de extensão afetar /api/...

Valide com:

curl -i http://localhost:8080/api/v1/users curl -i http://localhost:8080/api/file.png

Agora responda o exercício sobre o conteúdo:

Em uma configuração com um location por prefixo para "/static/" e uma regex que casa extensões como .css e .js, qual ajuste torna previsível que qualquer URL sob "/static/" seja tratada pelo bloco de "/static/", mesmo quando a regex também casaria?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Sem ^~, um regex pode substituir o melhor prefixo encontrado. Ao usar location ^~ /static/, o Nginx encerra a busca por regex quando esse prefixo casar, garantindo que /static/... use sempre o bloco de /static/.

Próximo capitúlo

Reverse proxy com Nginx: encaminhando para aplicações e serviços

Arrow Right Icon
Capa do Ebook gratuito Nginx para Iniciantes: Servidor Web, Reverse Proxy e Balanceamento Básico
46%

Nginx para Iniciantes: Servidor Web, Reverse Proxy e Balanceamento Básico

Novo curso

13 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.