O Nginx é um dos servidores Web mais populares do mundo. Ele é capaz de lidar com grandes cargas com muitas conexões de cliente simultâneas, e pode funcionar facilmente como um servidor Web, um servidor de e-mail ou um servidor de proxy reverso.
Neste guia, vamos discutir alguns dos detalhes dos bastidores que determinam como o Nginx processa as solicitações de clientes. A compreensão dessas ideias pode ajudar a eliminar a necessidade de suposições ao projetar servidores e blocos de localização e pode tornar o processamento de solicitações menos imprevisível.
O Nginx divide logicamente as configurações destinadas a atender diferentes conteúdo em blocos, que operam em uma estrutura hierárquica. Cada vez que uma solicitação de cliente é feita, o Nginx começa um processo para determinar quais blocos de configuração devem ser usados para lidar com a solicitação. Este processo de decisão é o que discutiremos neste guia.
Os principais blocos que discutiremos são o bloco de servidor e o bloco de localização.
Um bloco de servidor é um subconjunto da configuração do Nginx que define um servidor virtual usado para manusear solicitações de um determinado tipo. Os administradores geralmente configuram vários blocos de servidor e decidem qual bloco deve lidar com qual conexão com base no nome de domínio, porta e endereço IP solicitados.
Um bloco de localização fica dentro de um bloco de servidor e é usado para definir como o Nginx deve manusear solicitações para diferentes recursos e URIs para o servidor pai. O espaço URI pode ser subdividido da maneira que o administrador preferir usando esses blocos. Ele é um modelo extremamente flexível.
Como o Nginx permite que o administrador defina vários blocos de servidor que funcionam como instâncias de servidor Web separadas, ele precisa de um procedimento para determinar qual desses blocos de servidor será usado para satisfazer uma solicitação.
Ele faz isso através de um sistema definido de verificações que são usadas para encontrar a melhor combinação possível. As principais diretivas do bloco de servidor com as quais o Nginx se preocupa durante esse processo são a diretiva listen
(escuta) e a diretiva server_name
(nome do servidor).
Primeiramente, o Nginx analisa o endereço IP e a porta da solicitação. Ele compara esses valores com a diretiva listen
de cada servidor para construir uma lista dos blocos de servidor que podem resolver a solicitação.
A diretiva listen
tipicamente define quais endereços IP e portas que serão respondidos pelo bloco de servidor. Por padrão, qualquer bloco de servidor que não inclua uma diretiva listen
recebe os parâmetros de escuta de 0.0.0.0:80
(ou 0.0.0.0:8080
se o Nginx estiver sendo executado por um usuário normal, não root). Isso permite que esses blocos respondam a solicitações em qualquer interface na porta 80, mas esse valor padrão não possui muito peso dentro do processo de seleção de servidor.
A diretiva listen
pode ser definida como:
Geralmente, a última opção só terá implicações ao passar solicitações entre servidores diferentes.
Ao tentar determinar para qual bloco de servidor enviar uma solicitação, o Nginx primeiro tentará decidir com base na especificidade da diretiva listen
usando as seguintes regras:
listen
“incompletas” substituindo valores que estão faltando pelos seus valores padrão para que cada bloco possa ser avaliado por seu endereço IP e porta. Alguns exemplos dessas traduções são:
listen
usa o valor 0.0.0.0:80
.111.111.111.111
sem porta se torna 111.111.111.111:80
8888
sem endereço IP torna-se 0.0.0.0:8888
0.0.0 0
como endereço IP (para corresponder a qualquer interface), não será selecionado se houver blocos correspondentes que listam um endereço IP específico. Em todo caso, a porta deve ser exatamente a mesma.server_name
de cada bloco de servidor.É importante entender que o Nginx avaliará apenas a diretiva server_name
quando precisar distinguir entre blocos de servidor que correspondem ao mesmo nível de especificidade na diretiva listen
. Por exemplo, se o example.com
for hospedado na porta 80
de 192.168.1.10
, uma solicitação para example.com
será sempre atendida pelo primeiro bloco neste exemplo, apesar da diretiva server_name
no segundo bloco.
server {
listen 192.168.1.10;
. . .
}
server {
listen 80;
server_name example.com;
. . .
}
Caso mais de um bloco de servidor corresponda com o mesmo nível de especificidade, o próximo passo é verificar a diretiva server_name
.
Em seguida, para avaliar ainda mais as solicitações que possuem diretivas listen
igualmente específicas, o Nginx verifica o cabeçalho “Host” da solicitação. Esse valor possui o domínio ou endereço IP que o cliente estava tentando realmente alcançar.
O Nginx tenta achar a melhor correspondência para o valor que ele encontra olhando a diretiva server_name
dentro de cada um dos blocos de servidor que ainda são candidatos a seleção. O Nginx avalia eles usando a seguinte fórmula:
server_name
que corresponda exatamente ao valor no cabeçalho “Host” da solicitação. Se for encontrado, o bloco associado será usado para atender à solicitação. Se mais de uma correspondência exata for encontrada, a primeira é usada.server_name
correspondente usando um curinga inicial (indicado por um *
no início do nome na configuração). Se for encontrado, o bloco será usado para atender à solicitação. Se várias correspondências forem encontradas, a correspondência mais longa será usada para atender à solicitação.server_name
correspondente usando um curinga à direita (indicado por um nome de servidor que termina com um *
na configuração). Se for encontrado, o bloco será usado para atender à solicitação. Se várias correspondências forem encontradas, a correspondência mais longa será usada para atender à solicitação.server_name
usando expressões regulares (indicado por um ~
antes do nome). O primeiro server_name
com uma expressão regular que corresponda ao cabeçalho “Host” será usado para atender à solicitação.Cada combinação de endereço IP/porta possui um bloco de servidor padrão que será usado quando um plano de ação não puder ser determinado com os métodos acima. Para uma combinação de endereço IP/porta, ele será o primeiro bloco na configuração ou o bloco que contém a opção default_server
como parte da diretiva listen
(que iria se sobrepor ao algoritmo encontrado por primeiro). Pode haver apenas uma declaração default_server
para cada combinação de endereço IP/porta.
Se houver um server_name
definido que corresponda exatamente ao valor de cabeçalho “Host”, o bloco de servidor é selecionado para processar a solicitação.
Neste exemplo, se o cabeçalho “Host” da solicitação fosse definido como ”host1.example.com”, o segundo servidor seria selecionado:
server {
listen 80;
server_name *.example.com;
. . .
}
server {
listen 80;
server_name host1.example.com;
. . .
}
Se nenhuma correspondência exata for encontrada, o Nginx então verifica se há um server_name
com um curinga inicial que se encaixa. A correspondência mais longa que começa com um curinga será selecionada para atender à solicitação.
Neste exemplo, se a solicitação tivesse um cabeçalho “Host” de ”www.example.org”, o segundo bloco de servidor seria selecionado:
server {
listen 80;
server_name www.example.*;
. . .
}
server {
listen 80;
server_name *.example.org;
. . .
}
server {
listen 80;
server_name *.org;
. . .
}
Se nenhuma correspondência for encontrada com um curinga inicial, o Nginx então verá se uma correspondência existe usando um curinga no final da expressão. Neste ponto, a correspondência mais longa que termina com um curinga será selecionada para atender à solicitação.
Por exemplo, se a solicitação tiver um cabeçalho “Host” definido como ”www.example.com”, o terceiro bloco de servidor será selecionado:
server {
listen 80;
server_name host1.example.com;
. . .
}
server {
listen 80;
server_name example.com;
. . .
}
server {
listen 80;
server_name www.example.*;
. . .
}
Se nenhuma correspondência com curingas puder ser encontrada, o Nginx então seguirá adiante para tentar corresponder o termo com as diretivas do server_name
que usam expressões regulares. A primeira expressão regular correspondente será selecionada para responder à solicitação.
Por exemplo, se o cabeçalho “Host” da solicitação for definido como ”www.example.com”, então o segundo bloco de servidor será selecionado para satisfazer a solicitação:
server {
listen 80;
server_name example.com;
. . .
}
server {
listen 80;
server_name ~^(www|host1).*\.example\.com$;
. . .
}
server {
listen 80;
server_name ~^(subdomain|set|www|host1).*\.example\.com$;
. . .
}
Se nenhum dos passos acima for capaz de satisfazer a solicitação, então a solicitação será passada ao servidor padrão para o endereço IP e porta correspondentes.
De maneira similar ao processo que o Nginx usa para selecionar o bloco de servidor que processará uma solicitação, o Nginx também possui um algoritmo estabelecido para decidir qual bloco de localização dentro do servidor usar para manusear solicitações.
Antes de abordarmos como o Nginx decide qual bloco de localização usar para manusear solicitações, vamos analisar algumas das sintaxes que podem ser vistas nas definições de blocos de localização. Os blocos de localização localizam-se dentro de blocos de servidor (ou outros blocos de localização) e são usados para decidir como processar o URI de solicitação (a parte da solicitação que vem após o nome de domínio ou endereço IP/porta).
Os blocos de localização geralmente possuem a seguinte forma:
location optional_modifier location_match {
. . .
}
O location_match
no exemplo acima define com o que o Nginx deve comparar o URI de solicitação. A existência ou não existência do modificador no exemplo acima afeta a maneira como o Nginx tenta corresponder o bloco de localização. Os modificadores abaixo farão com que o bloco de localização associado seja interpretado da seguinte forma:
=
: se um sinal de igual for usado, o bloco será considerado uma correspondência se o URI de solicitação corresponder exatamente ao local dado.~
: se um modificador til estiver presente, o local será interpretado como uma correspondência de expressão regular sensível a maiúsculas e minúsculas.~*
: se um modificador de til e asterisco for usado, o bloco de localização será interpretado como uma correspondência de expressão regular que não diferencia maiúsculas de minúsculas.^~
: se um modificador de acento circunflexo e til estiver presente, e se este bloco for selecionado como a melhor correspondência de expressão não regular, a correspondência de expressão regular não será realizada.Como um exemplo de correspondência de prefixos, o bloco de localização a seguir pode ser selecionado para responder aos URIs de solicitação que se pareçam com /site
, /site/page1/index.html
ou /site/index.html
:
location /site {
. . .
}
Para demonstrar a correspondência exata de URIs de solicitação, esse bloco será sempre usado para responder a um URI de solicitação que se pareça com /page1
. Ele não será usado para responder a um URI de solicitação /page1/index.html
. Lembre-se de que se esse bloco for selecionado e a solicitação for realizada usando uma página de índice, um redirecionamento interno será feito para outro local. Ele será o manuseador real da solicitação:
location = /page1 {
. . .
}
Como um exemplo de um local que deve ser interpretado como uma expressão regular sensível a maiúsculas e minúsculas, este bloco poderia ser usado para manusear solicitações para /tortoise.jpg
, mas não para /FLOWER.PNG
:
location ~ \.(jpe?g|png|gif|ico)$ {
. . .
}
Um bloco que permitiria a correspondência sem diferenciar maiúsculas de minúsculas parecido com o exemplo acima é mostrado abaixo. Aqui, tanto /tortoise.jpg
quanto /FLOWER.PNG
poderiam ser manuseados por este bloco:
location ~* \.(jpe?g|png|gif|ico)$ {
. . .
}
Por fim, este bloco impediria a ocorrência de correspondências de expressão regular se ele fosse escolhido como a melhor correspondência de expressão não regular. Ele poderia manusear solicitações para /costumes/ninja.html
:
location ^~ /costumes {
. . .
}
Como se vê, os modificadores indicam como o bloco de localização deve ser interpretado. No entanto, isso não nos informa qual algoritmo o Nginx usa para decidir para qual bloco de localização enviar a solicitação. Vamos analisar isso a seguir.
O Nginx escolhe o local que será usado para atender a uma solicitação de forma semelhante a como seleciona um bloco de servidor. Ele executa um processo que determina o melhor bloco de localização para qualquer solicitação. Entender esse processo é um requisito crucial para ser capaz de configurar o Nginx de maneira confiável e precisa.
Tendo em mente os tipos de declaração de localização que descrevemos acima, o Nginx avalia os possíveis contextos de localização comparando o URI de solicitação com cada um dos locais. Ele faz isso usando o seguinte algoritmo:
=
for encontrado para corresponder exatamente ao URI de solicitação, este bloco de localização é selecionado imediatamente para atender à solicitação.=
) for encontrada, o Nginx então passa a avaliar prefixos não exatos. Ele descobre o prefixo de correspondência mais longo para um determinado URI de solicitação, que é então avaliado da seguinte forma:
^~
, então o Nginx imediatamente terminará sua pesquisa e selecionará esse local para atender à solicitação.^~
, a correspondência é armazenada pelo Nginx por enquanto, para que o foco da pesquisa possa mudar.É importante entender que, por padrão, o Nginx atenderá correspondências por expressão regular preferencialmente em relação a correspondências por prefixo. No entanto, ele avalia primeiro as localizações de prefixos, permitindo que o administrador altere essa tendência especificando localizações usando os modificadores =
e ^~
.
Também é importante notar que, embora as localizações de prefixo geralmente selecionarem com base na correspondência mais longa e específica, a avaliação de expressões regulares é interrompida quando a primeira localização correspondente é encontrada. Isso significa que o posicionamento dentro da configuração tem vastas implicações para as localizações de expressões regulares.
Por fim, é importante entender que as correspondências por expressões regulares dentro da correspondência de prefixo mais longa “passam à frente” quando o Nginx avalia as localizações de regex. Elas serão avaliadas, por ordem, antes de qualquer uma das outras correspondências por expressão regular serem consideradas. Maxim Dounin, um desenvolvedor do Nginx incrivelmente prestativo, explica nesta postagem essa parte do algoritmo de seleção.
De maneira geral, quando um bloco de localização é selecionado para atender a uma solicitação, a solicitação é manuseada inteiramente dentro desse contexto a partir daquele ponto. Apenas a localização selecionada e as diretivas herdadas determinam como a solicitação é processada, sem a interferência de blocos de localização irmãos.
Embora essa seja uma regra geral que permite projetar seus blocos de localização de maneira previsível, é importante perceber que há momentos em que uma nova procura de localização é acionada por determinadas diretivas dentro da localização selecionada. As exceções à regra de “apenas um bloco de localização” podem ter implicações sobre como a solicitação é realmente atendida e podem não se alinhar com as expectativas que você tinha quando projetou seus blocos de localização.
Algumas diretivas que podem levar a esse tipo de redirecionamento interno são:
Vamos analisa-los brevemente.
A diretiva index
sempre leva a um redirecionamento interno se for usada para processar a solicitação. As correspondências exatas de localização são frequentemente usadas para acelerar o processo de seleção por finalizarem imediatamente a execução do algoritmo. No entanto, se você fizer uma correspondência exata de localização que é um diretório, existe uma boa chance de a solicitação ser redirecionada para uma localização diferente para ser de fato processada.
Neste exemplo, a primeira localização corresponde a um URI de solicitação /exact
, mas, para manusear a solicitação, a diretiva index
herdada pelo bloco inicia um redirecionamento interno para o segundo bloco:
index index.html;
location = /exact {
. . .
}
location / {
. . .
}
No caso acima, se fosse realmente necessário que a execução permanecesse no primeiro bloco, você precisaria escolher um método diferente para satisfazer a solicitação para o diretório. Por exemplo, você poderia definir um index
inválido para esse bloco e ativar o autoindex
:
location = /exact {
index nothing_will_match;
autoindex on;
}
location / {
. . .
}
Essa é uma maneira de impedir que o index
mude os contextos, mas provavelmente não é útil para a maioria das configurações. Geralmente, uma correspondência exata nos diretórios pode ser útil para coisas como reescrever a solicitação (que também resulta em uma nova pesquisa de localização).
Outra situação onde a localização de processamento pode ser reavaliada é com a diretiva try_files
. Essa diretiva diz ao Nginx para verificar a existência de um conjunto de arquivos ou diretórios nomeados. O último parâmetro pode ser um URI para o qual o Nginx fará um redirecionamento interno.
Considere a configuração a seguir:
root /var/www/main;
location / {
try_files $uri $uri.html $uri/ /fallback/index.html;
}
location /fallback {
root /var/www/another;
}
No exemplo acima, se uma solicitação for feita para /blahblah
, a primeira localização inicialmente receberá a solicitação. Ele tentará encontrar um arquivo chamado blahblah
no diretório /var/www/main
. Se ele não puder encontrar um, ele seguirá procurando por um arquivo chamado blahblah.html
. Em seguida, ele tentará ver se há um diretório chamado blahblah/
dentro do diretório /var/www/main
. Se todas essas tentativas falharem, ele redirecionará para /fallback/index.html
. Isso desencadeará outra pesquisa de localização que será capturada pelo segundo bloco de localização. Isso atenderá o arquivo /var/www/another/fallback/index.html
.
Outra diretiva que pode levar a uma mudança de bloco de localização é a rewrite
. Quando se usa o último
parâmetro com a diretiva rewrite
, ou quando não se usa nenhum parâmetro, o Nginx procurará uma nova localização correspondente com base nos resultados de rewrite.
Por exemplo, se modificarmos o último exemplo para incluir uma rewrite, é possível ver que a solicitação às vezes é passada diretamente para a segunda localização sem depender da diretiva try_files
:
root /var/www/main;
location / {
rewrite ^/rewriteme/(.*)$ /$1 last;
try_files $uri $uri.html $uri/ /fallback/index.html;
}
location /fallback {
root /var/www/another;
}
No exemplo acima, uma solicitação para /rewriteme/hello
será manuseada inicialmente por um primeiro bloco de localização. Ela será reescrita para /hello
e uma localização será pesquisada. Neste caso, ela corresponderá novamente à primeira localização e será processada pelo try_files
como de costume, talvez retornando para /fallback/index.html
se nada for encontrado (usando o redirecionamento interno do try_files
que discutimos acima).
No entanto, se uma solicitação for feita para /rewriteme/fallback/hello
, o primeiro bloco novamente corresponderá. A diretiva rewrite é aplicada novamente, dessa vez resultando em /fallback/hello
. A solicitação será então atendida a partir do segundo bloco de localização.
Uma situação relacionada acontece com a diretiva return
ao enviar os códigos de status 301
ou 302
. Neste caso, a diferença é que isso resulta em uma solicitação inteiramente nova na forma de um redirecionamento visível externamente. Essa mesma situação pode ocorrer com a diretiva rewrite
ao usar os sinalizadores redirect
ou permanent
. No entanto, essas pesquisas de localização não devem ser inesperadas, uma vez que os redirecionamentos visíveis externamente sempre resultam em uma nova solicitação.
A diretiva error_page
pode levar a um redirecionamento interno parecido com aquele criado por try_files
. Essa diretiva é usada para definir o que deve acontecer quando certos códigos de status são encontrados. Isso provavelmente nunca será executado se o try_files
estiver definido, já que essa diretiva manuseia todo o ciclo de vida de uma solicitação.
Considere este exemplo:
root /var/www/main;
location / {
error_page 404 /another/whoops.html;
}
location /another {
root /var/www;
}
Todas as solicitações (que não sejam aquelas que começam com /another
) serão manuseadas pelo primeiro bloco, que atenderá arquivos em /var/www/main
. No entanto, se um arquivo não for encontrado (um status 404), um redirecionamento interno para /another/whoops.html
ocorrerá, levando a uma nova pesquisa de localização que eventualmente chegará no segundo bloco. Este arquivo será atendido por /var/www/another/whoops.html
.
Como se vê, entender as circunstâncias nas quais o Nginx aciona uma nova pesquisa de localização pode ajudar a prever o comportamento que você verá ao fazer solicitações.
Compreender as maneiras como o Nginx processa as solicitações de clientes pode tornar seu trabalho como um administrador muito mais fácil. Você será capaz de saber qual bloco de servidor o Nginx selecionará com base em cada solicitação de cliente. Você também será capaz de dizer como o bloco de localização será selecionado com base no URI de solicitação. De maneira geral, saber como o Nginx seleciona diferentes blocos lhe dará a capacidade de rastrear os contextos que o Nginx aplicará para atender a cada solicitação.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!