DEV Community

Cover image for Série Nginx #3: Conhecendo as diretivas
Valdeir S.
Valdeir S.

Posted on

Série Nginx #3: Conhecendo as diretivas

Diretivas do Nginx

Olá, galerinha, pronto para mais uma postagem? 🥳

Vamos conhecer e aprender como utilizar algumas das diretivas mais importantes do Nginx.

De acordo com a documentação oficial, o nginx consiste em módulos controlados por diretivas especificadas nos arquivos de configuração. Elas são divididas em diretivas simples e diretivas em bloco.

Uma diretiva simples consiste no nome e nos parâmetros separados por espaços e com um ponto e vírgula (;) no final.

Uma diretiva de bloco permite que o desenvolvedor utilize outras diretivas dentro de chaves ({ e }). Quando isso ocorre, essa diretiva de bloco é chamada de contexto (exemplos: events, http, server e location).

Vamos conhecer as diretivas.


add_header (fonte)

Como o nome deixa claro, essa diretiva serve para definir headers direto do Nginx. Isso é útil para definir os cabeçalhos de CORS, por exemplo.

# Syntax: add_header name value [always];
# Default: —
# Context: http, server, location, if in location
#
location /upload {
    add_header "Access-Control-Allow-Origin" "https://*.valdeir.dev";
    add_header "Access-Control-Allow-Methods" "GET, OPTIONS";
    add_header X-Dev "Valdeir Psr" always;
}
Enter fullscreen mode Exit fullscreen mode

O cabeçalho da requisição acima será:

http http://php.valdeirpsr.com.br/upload/foto.jpg
HTTP/1.1 200 OK
Content-Length: 1333425
Content-Type: image/jpeg
Date: Fri, 27 Aug 2021 15:28:23 GMT
access-control-allow-methods: GET, OPTIONS
access-control-allow-origin: https://*.valdeir.dev
x-dev: Valdeir Psr

+-----------------------------------------+
| NOTE: binary data not shown in terminal |
+-----------------------------------------+
Enter fullscreen mode Exit fullscreen mode

alias (fonte)

Com a diretiva alias, podemos substituir a localização da pasta definida na diretiva root.

root /var/www/html;

location /css {
    # Syntax: alias path;
    # Default: —
    # Context: location
    #
    alias /dev/vda2/css/;
}
Enter fullscreen mode Exit fullscreen mode

Isso significa que a requisição https://valdeir.psr/css/global.css carregará os arquivos da pasta /dev/vda2/css.

HTTP File
https://valdeir.psr/css/global.css /dev/vda2/css/global.css
https://valdeir.psr/images/logo.svg /var/www/html/images/logo.svg

client_max_body_size (fonte)

Você pode usar essa diretiva para configurar o tamanho máximo do corpo da requisição. Útil para limitar o tamanho de arquivos em formulários de upload. Caso o valor definido seja 0, desabilita a verificação do tamanho dos dados enviados.

# Syntax: client_max_body_size size;
# Default: client_max_body_size 1m;
# Context: http, server, location
#
client_max_body_size 1G;
Enter fullscreen mode Exit fullscreen mode

error_page (fonte)

A diretiva permite a customização de uma página de erro. Quando a página retornar o erro 404, por exemplo, então o Nginx irá retornar para o usuário o arquivo /not_found.html.

# Syntax: error_page code ... [=[response]] uri;
# Default: —
# Context: http, server, location
#
error_page 404             /not_found.html
error_page 500 502 503 504 /50x.html;
Enter fullscreen mode Exit fullscreen mode

Também é possível redirecionar o usuário para outra página ou domínio com um novo status code

server_name valdeir.dev;

error_page 401 =200 https://auth.$server_name;
Enter fullscreen mode Exit fullscreen mode

Observação: O parâmetro code não pode ser igual a 499, menor que 300 ou maior que 599.


listen (fonte)

Essa diretiva permite definir qual o endereço e/ou porta o Nginx deverá "ouvir" as requisições. Por padrão, o servidor usará as portas 80 e 8000.

# Syntax address: listen address[:port] [default_server] [ssl] [http2];
#
# Syntax port: listen port [default_server] [ssl] [http2];
#
# Syntax PID: listen unix:path [default_server] [ssl] [http2];
#
# Default: listen *:80 | *:8000;
# Context: server
#
listen 80;
listen [::]:80;
listen 443 ssl;
listen [::]:443 ssl;
Enter fullscreen mode Exit fullscreen mode

Parâmetros adicionais

default_server
Informa se o servidor virtual é o padrão. Caso o parâmetro não seja informado, o primeiro servidor localizado será definido como padrão. Você pode utilizar esse parâmetro apenas em um servidor virtual.
ssl
Esse parâmetro informa se o servidor deve receber conexões criptografadas. Lembrando que, ao utilizar esse parâmetro, é importante configurar as diretivas ssl_certificate e ssl_certificate_key com as chaves para que o Nginx consiga descritografar as informações e repassá-las à aplicação.
http2
Indica que o Nginx deve aceitar conexões com o protocolo HTTP/2. Lembrando que o SSL é obrigatório para o uso desse protocolo.

location (fonte)

A diretiva mais utilizada. Ela serve para aplicar configurações de acordo com a URI da requisição, que pode ser identificada com o uso de expressões regulares ou correspondência exata.

# Syntax: location [ = | ~ | ~* | ^~ ] uri { ... }
#         location @name { ... }
# Default: —
# Context: server, location
#
Enter fullscreen mode Exit fullscreen mode

Utilizando os modificadores

O uso do modificador = indica que as configurações deverão ser aplicadas apenas quando a URI for exatamente igual ao valor informado no parâmetro URI. No exemplo abaixo, as configurações serão aplicadas na URI /upload, porém não serão aplicadas na URI /upload/avatar.svg, por exemplo.

location = /upload {
    ...
}
Enter fullscreen mode Exit fullscreen mode

O uso do modificador ~ indica que as configurações deverão ser aplicadas quando a URI for correspondente à expressão regular definida na diretiva. No exemplo abaixo, as configurações serão aplicadas nas URI /upload/avatar.jpeg, /upload/avatar.jpg, /upload/avatar.gif e /upload/avatar.webp, porém não serão aplicadas nas URI /upload/avatar.mp4, /upload/avatar.jpg.avif ou /UPLOAD/avatar.jpg.

location ~ /upload/.*\.(jpe?g|gif|webp)$ {
    ...
}
Enter fullscreen mode Exit fullscreen mode

O modificador ~* funciona da mesma forma que ~. A diferença é que essa é case-insensitive e esta, não; ou seja, utilizando o modificador ~*, a URI /upload/avatar.jpg e /UPLOAD/avatar.jpg serão processadas igualmente.

location ~* /upload/.*\.(jpe?g|gif|webp)$ {
    ...
}
Enter fullscreen mode Exit fullscreen mode

O modificador ^~ determina que o NGINX deverá parar de pesquisar correspondências mais específicas e utilizar essa diretiva.

location ^~ /upload/.*\.(jpe?g|gif|webp)$ {
    # Para aqui e não continua
}

location ~* \.(jpe?g|gif|webp)$ {
    ...
}
Enter fullscreen mode Exit fullscreen mode

Caso nenhum modificador seja utilizado, o Nginx comparará o início da URI com parte da URL. No exemplo abaixo, as configurações da diretiva location serão aplicadas em /upload, /upload/avatar.jpg e /uploadsssss/avatar.jpg, por exemplo. Esse modo diferencia maiúscula de minúscula.

location /upload {
    ...
}
Enter fullscreen mode Exit fullscreen mode

Capturando grupos de RegEx

Na diretiva location, você pode capturar os grupos definidos em sua RegEx. Isso é útil para tornar as configurações dinâmicas.

root /var/www/html;

location ~* /profile/([^/]+).jpg {
    alias /dev/vda2/users/$1/avatar.jpg;
}
Enter fullscreen mode Exit fullscreen mode

No exemplo acima, informamos que requisições com a URI /profile/qualquer-coisa.jpg será apontada para o arquivo /dev/vda2/users/qualquer-coisa/avatar.jpg.


Nomeando location

Nomear a diretiva location é importante para reutilizá-la em outras partes do código ou quebrar as regras em pedaços para facilitar a manutenção e/ou leitura dos arquivos de configuração. A sintaxe é semelhante as que já foram mostradas. A diferença está no parâmetro @.

location / {
    try_files $uri $uri/ @opencart;
}

location ~ ^/sitemap.xml$ {
    try_files $uri @opencart;
}

location @opencart {
    rewrite ^/sitemap.xml$ /index.php?route=extension/feed/google_sitemap last;

    rewrite ^/(.+)$ /index.php?_route_=$1 last;
}
Enter fullscreen mode Exit fullscreen mode

map (fonte)

A diretiva map permite criar variáveis de acordo com um mapeamento feito através de valores key:value definidos nela. É útil para tornar as configurações dinâmicas.

No exemplo abaixo, utilizamos a variável $http_user_agent, que é nativa do Nginx, para capturar o User Agent do usuário e comparar com as chaves. Se a variável do Nginx for igual à chave, então define um valor na variável a ser criada.

# Syntax: map $variable_nginx $variable_name { ... }
# Default: —
# Context: http
#
map $http_user_agent $ua_blocked {
    default 0; # Parâmetro

    ~Jorgee 1; # Block "Jorgee", "One Jorgee Two"
    ~ZmEu   1;
    ~*Spam  1; # Block "SPAM", "One spam Two"
    ~*Scan  1;
    Scanner 1; # Block "Scanner", but not "PSR-Scanner"
    Wget    1;
    curl    1;
}

server {
    if ($ua_blocked) {
        return 403;
    }
}
Enter fullscreen mode Exit fullscreen mode

No exemplo acima, se a variável $http_user_agent for igual à Jorgee, ZmEu, Spam etc., define o valor 1 à variável $ua_blocked. Caso valor nenhum coincida, utiliza o valor do parâmetro default.

Ao usar ~ ou ~*, você indica que o Nginx deve tratar a chave como expressão regular case-sensitive e case-insensitive, respectivamente. Não usá-las, indica que a correspondência deve ser exata.

Parâmetros do map

default <valor>
Define um valor padrão que retornará quando as regras não corresponderem às chaves definidas.
include <arquivo>
Inclui um arquivo com valores. Pode haver várias inclusões.
volatile
Indica que a variável não pode ser armazenada em cache.
hostnames
Indica que os valores de origem podem ser nomes de host com um prefixo ou máscara de sufixo.

Funcionamento do map

Se houver mais de uma correspondência, o Nginx seguirá a ordem abaixo:

  1. Valor string sem máscara;
  2. Valor da string mais longa com uma máscara de prefixo, por exemplo: *.example.com;
  3. Valor da string mais longa com uma máscara de sufixo, por exemplo, mail.*;
  4. Primeiro valor encontrado com a expressão regular;
  5. Valor do parâmetro default.

return (fonte)

Ao utilizar essa diretiva, o Nginx irá parar o processamento e retornará um valor definido ou um redirecionamento de página.

No exemplo abaixo, ao utilizar o código de status 301 ou 302 ou apenas uma URL, o Nginx informará ao navegador que o cliente deve ser redirecionado para a URL informada.

Ao utilizar o código de status 444, o Nginx fechará a conexão e não retornará uma resposta.

Em qualquer outro código de status, o Nginx retornará o texto como o corpo da resposta.

# Syntax: return code [text];
#         return [301|302] URL;
# Default: —
# Context: server, location, if
#

location /retorna {
    return 200 "Corpo da Mensagem";
}

location /movido-permanente {
    return 301 https://another-url.com;
}

location /movido-temporario {
    return $scheme://auth.$server_name; # Equivale a https://auth.valdeir.dev
}

location /fechado {
    return 444;
}
Enter fullscreen mode Exit fullscreen mode

rewrite (fonte)

A diretiva permite reescrever a URI internamente ou redirecionar o usuário para outra página utilizando o status code 301 ou 302. Caso haja mais de uma diretiva rewrite, a URI poderá ser substituída/processada até a última diretiva ou conforme o uso das flags.

# Syntax: rewrite regex replacement [flag];
# Default: —
# Context: server, location, if
#
rewrite ^/sitemap.xml$ /index.php?route=extension/feed/google_sitemap last;
Enter fullscreen mode Exit fullscreen mode

Flag (opcional)

last
Para o processamento atual e busca um bloco location que corresponda à nova URI.
break
Para o processamento atual e retorna a resposta para o usuário.
redirect
Informa ao navegador que o usuário deverá ser redirecionado se o parâmetro replacement iniciar com https://, http:// ou a variável $scheme. O redirecionamento deverá ser feito com o status code 302
permanent
Informa ao navegador que o usuário deverá ser redirecionado se o parâmetro replacement iniciar com https://, http:// ou a variável $scheme. O redirecionamento deverá ser feito com o status code 301

Quando usar last ou break?

Como explicado, o last buscará um novo bloco location para tratar a URI substituída. Caso utilize essa flag dentro do contexto location, o Nginx poderá entrar em um loop infinito e gerar o erro 500. Portanto, quando possível, opte por break quando estiver no contexto do location; e, last, server.

server {
    rewrite ^/upload/(.*)$ /upload/foto/$1 last;
}

location /static/(.*) {
    rewrite ^/static/(.*)$ /static/foto/$1 break; # O `break` evita o erro 500
}
Enter fullscreen mode Exit fullscreen mode

Atenção! O grupo capturado na RegExp pode ser substituído ao usar map. Para resolver, você pode usar um nome para o grupo ou criar uma variável antes de usar a diretiva rewrite.

# Permite que o Nginx retorne uma imagem otimizada de acordo com o navegador
# Para saber mais, acesse o link <link-do-próximo-artigo>
#
map $uri $file_ext {
    ...
}

location /upload {
    set $file_extension $file_ext;

    rewrite ^/upload/(.*)\..+$ "/static/$1$file_extension" break;
}
Enter fullscreen mode Exit fullscreen mode

root (fonte)

Define o diretório para as requisições. No exemplo abaixo, ao acessar a URI /css, o Nginx carregará o arquivo da pasta /dev/vda2/css/ em vez do diretório /var/www/html.

Caso a diretiva root não seja definida no escopo location, o Nginx buscará na diretiva server e caso não encontre, buscará na diretiva http.

server {
    # Syntax: root path;
    # Default: root html;
    # Context: http, server, location, if in location
    #
    root /var/www/html;

    location /css {
        root /dev/vda2/css;
    }
}
Enter fullscreen mode Exit fullscreen mode

Quando usar alias e root?

O root adiciona a URI ao construir o caminho do arquivo, enquanto o alias modifica a URI. Além disso, o alias não pode estar dentro do contexto location nomeado e não pode usar a variável $realpath_root.

# Na requisição `/foto/luisa.jpg`, o Nginx carregará o arquivo
# /var/www/html/static/foto/luisa.jpg
#
location /foto {
    root /var/www/html/static;
}

# Na requisição `/imagem/sonza.jpg`, o Nginx carregará o arquivo
# /var/www/html/static/sonza.jpg
#
location /imagem {
    alias /var/www/html/static/;
}
Enter fullscreen mode Exit fullscreen mode

server (fonte)

Essa diretiva em bloco serve para criar um servidor virtual.

# Syntax: server { ... }
# Default: —
# Context: http
#
server {
    server_name valdeir.dev www.valdeir.dev;
}
Enter fullscreen mode Exit fullscreen mode

server_name (fonte)

Define o nome/URL do servidor virtual criado. É possível definir mais de um nome quando separados por espaços. A diretiva, assim como rewrite e location, permite o uso de expressões regulares.

Criaremos abaixo um servidor virtual que receberá as requisições das URLS:

  • valdeir.dev
  • cdn.valdeir.dev
  • assets.valdeir.dev
  • qualquer-coisa.valdeir.cdn
server {
    # Syntax:  server_name name ...;
    # Default: server_name "";
    # Context: server
    #
    server_name valdeir.dev ~(cdn|assets)\.valdeir\.dev$ *.valdeir.cdn;
}
Enter fullscreen mode Exit fullscreen mode

Atenção! Para utilizar RegExp, é necessário que o Nginx tenha sido compilado com suporte à biblioteca PCRE.

Através da diretiva server_name, você pode criar variáveis de acordo com os grupos capturados na sua expressão regular.

server {
    server_name ~^(www\.)?(?<domain>.+)$;

    location / {
        root /sites/$domain;
    }
}

server {
    server_name _;

    location / {
        root /sites/default;
    }
}
Enter fullscreen mode Exit fullscreen mode

Ordem na busca pelos servidor

Quando há mais de um nome de servidor, o Nginx seguirá a seguinte ordem:

  1. Procurar pelo nome exato (valdeir.dev);
  2. Procurar pelo nome mais longo com o wildcard (*) como prefixo (*.valdeir.dev);
  3. Procurar pelo nome mais longo com o wildcard (*) como sufixo (valdeir.*);
  4. Procurar pela primeira ocorrência usando expressão regular.

Observação! Você, obviamente, deve cadastrar corretamente os dados de CDN que redirecione o site para seu servidor.


try_files (fonte)

Essa diretiva verificará se um arquivo existe seguindo a ordem pré-definida pelo administrador. O processamento é feito semelhante ao das diretivas alias e root. Ela permite também que o cliente possa acessar uma pasta quando o valor terminar com uma barra (/). Isso é útil quando o desenvolvedor utiliza a diretiva autoindex. Se arquivo nenhum for encontrado, o o usuário será redirecionado para outra página, URL ou bloco location nomeado.

root /var/www/html;

autoindex on;

location /upload {
    # Syntax: try_files file ... uri;
    #         try_files file ... =code;
    # Default: —
    # Context: server, location
    #
    try_files $uri $uri/ /empty.gif =444;
}
Enter fullscreen mode Exit fullscreen mode

No exemplo acima, ao acessar a requisição /upload/avatar.webp, o Nginx seguirá a seguinte ordem:

  1. Verifica se o arquivo /var/www/html/upload/avatar.webp existe; se não existir,
  2. Verifica se a pasta /var/www/html/upload/avatar.webp/ existe; se não existir,
  3. Verifica se o arquivo /var/www/html/empty.gif existe; se não existir,
  4. Fecha a conexão sem uma resposta (usando o =444).

É possível também utilizar bloco location nomeado.

location / {
  try_files $uri $uri/ @opencart;
}

location @opencart {
  rewrite ^/sitemap.xml$ /index.php?route=extension/feed/google_sitemap last;
  rewrite ^/googlebase.xml$ /index.php?route=extension/feed/google_base last;
  rewrite ^/system/storage/(.*) /index.php?route=error/not_found last;

  rewrite ^/(.+)$ /index.php?_route_=$1 last;
}

location ~* (\.twig|\.tpl|\.ini|\.log|(?<!robots)\.txt)$ {
  deny all;
}
Enter fullscreen mode Exit fullscreen mode

Conclusão

Essas foram as diretivas mais utilizadas no Nginx. Nas próximas postagens, aprenderemos como aumentar a segurança e a performance do nosso site. Beleza? 👍

Discussion (3)

Collapse
urielsouza29 profile image
Uriel dos Santos Souza

Oii!
Se sabe me dizer se é um bug ou erro meu em configuração do Nginx.
Tenho um VPS com 4 sites apenas!

2 com PHP já antigos e funcionando desde sempre com Nginx.

2 novos em node.

Mas acontece algo interessante.
Quando coloco o arquivo de configuração

siteEmNode.com.br
E dentro coloco todas as info corretas
Uso o Nginx como proxy no caso do Node.
Testo a config. Não tem erro.
Crio o link simbolico e restarto o nginx.

Ai vou acessar a URL siteEmNode.com.br
E aparece outro site que esta no meu server.
segundositeEMphp.com.br

A URL esta correta. E o site não!

Não tem erros. Ta tudo 100% correto.
E não aparece o site correto.

Então eu, vou lá e mudo siteEmNode.com.br para
default, crio o link simbólico, acesso o site siteEmNode.com.br
E aparece corretamente! Perfeito.

Ai eu fui lá e mudei o arquivo de default para > siteEmNode.com.br, criei o link simbólico.
E magicamente funcionou

Tive que por mais um site em node.
Deu o mesmo problema. Mas agora ainda não mudei default o nome do arquivo para o nome do site(por organização)

Se sabe me dizer se pode ser um erro de configuração
ou algum problema no nginx.
Pq uso PHP(servidor normal) e node(proxy)?

Abraços

Collapse
valdeirpsr profile image
Valdeir S. Author

Olá!!

É necessário verificar se o link simbólico foi criado no lugar correto na primeira vez (acontece).

Se você utilizar listen 80 default_server; em um dos arquivos de configuração, o Nginx considerará que todas as URL que apontem para o IP do servidor carreguem-no caso a URL não seja encontrada em outro servidor virtual.

Acho que fica mais fácil explicar o passo a passo.

  1. O cliente acessa "siteEmNode.com.br";
  2. O Nginx procurará um servidor virtual que contenha essa URL acessada;
  3. Se o Nginx encontrar o servidor virtual, ele aplicará as configurações dele;
  4. Se o Nginx não encontrar o servidor virtual, ele irá carregar o servidor padrão, que tem a flag default_server na diretiva listen.
  5. Se o Nginx não encontrar o servidor padrão, ele irá carregar o primeiro servidor virtual carregado.

"Tenho certeza que o symlink foi criado corretamente"

Neste caso, pode ser problema com cache do navegador ou CDN (CloudFlare, Akamai, Sucuri etc)

"Não é. Limpei os caches, habilitei o modo de desenvolvimento e estou no modo anônimo/privado do navegador"

Aí é um pouco mais complexo. Recomendo configurar o log de erro para o modo debug e verificar como o Nginx está carregando os arquivos de configuração.

  1. Verifique se o Nginx está carregando seu arquivo com nginx -T;
  2. Adicione a diretiva error_log /var/log/nginx/debug.log debug; no contexto http;
  3. Reinicie o Nginx;
  4. Verifique os logs.
Collapse
urielsouza29 profile image
Uriel dos Santos Souza

Só uso a porta 443. Nunca a 80.
Ma irei ver melhor tudo que vc falou.
Obrigado!