Nginx es uno de los servidores web más populares del mundo. Puede manejar correctamente altas cargas con muchas conexiones de clientes concurrentes y puede funcionar fácilmente como servidor web, servidor de correo o servidor de proxy inverso.
En esta guía, explicaremos algunos de los detalles en segundo plano que determinan cómo Nginx procesa las solicitudes de los clientes. Entender estas ideas puede ayudar a despejar las incógnitas sobre el diseño de bloques de servidores y ubicación, y puede hacer que el manejo de las solicitudes parezca menos impredecible.
Nginx divide de forma lógica las configuraciones destinadas a entregar distintos contenidos en bloques, que conviven en una estructura jerárquica. Cada vez que se realiza una solicitud de cliente, Nginx inicia un proceso para determinar qué bloques de configuración deben usarse para gestionar la solicitud. Este proceso de decisión es lo que explicaremos en esta guía.
Los bloques principales que explicaremos son el bloque de servidor y el bloque de ubicación.
Un bloque de servidor es un subconjunto de la configuración de Nginx que define un servidor virtual utilizado para gestionar las solicitudes de un tipo definido. Los administradores suelen configurar varios bloques de servidores y decidir qué bloque debe gestionar cada conexión según el nombre de dominio, el puerto y la dirección IP solicitados.
Un bloque de ubicación reside dentro de un bloque de servidor y se utiliza para definir la manera en que Nginx debe gestionar las solicitudes para diferentes recursos y URI para el servidor principal. El espacio URI puede subdividirse de la manera que el administrador quiera utilizando estos bloques. Es un modelo extremadamente flexible.
Dado que Nginx permite que el administrador defina varios bloques de servidores que funcionan como instancias de servidores web virtuales independientes, necesita un procedimiento para determinar cuál de estos bloques de servidores se utilizará para satisfacer una solicitud.
Lo hace mediante un sistema definido de comprobaciones que se utilizan para encontrar la mejor coincidencia posible. Las principales directivas de bloques de servidores de las que se ocupa Nginx durante este proceso son la directiva listen
y la directiva server_name
.
Primero, Nginx examina la dirección IP y el puerto de la solicitud. Luego, lo compara con la directiva listen
de cada servidor para crear una lista de los bloques de servidores que pueden resolver la solicitud.
La directiva listen
generalmente define la dirección IP y el puerto a los que responderá el bloque de servidor. De manera predeterminada, cualquier bloque de servidor que no incluya una directiva listen
recibe los parámetros de escucha 0.0.0.0:80
(o 0.0.0.0:8080
si Nginx está siendo ejecutado por un usuario no root regular). Eso permite que estos bloques respondan a las solicitudes en cualquier interfaz en el puerto 80, pero este valor predeterminado no afecta demasiado al proceso de selección de servidores.
La directiva listen
puede establecerse para las siguientes características:
La última opción, por lo general, solo tendrá implicaciones al pasar solicitudes entre distintos servidores.
Cuando intente determinar a qué bloque de servidor enviar una solicitud, Nginx tratará primero de decidir según la especificidad de la directiva listen
usando las siguientes reglas:
listen
“incompletas” sustituyendo los valores que faltan por sus valores predeterminados para que cada bloque pueda evaluarse por su dirección IP y su puerto. Algunos ejemplos de estas traslaciones son:
listen
utiliza el valor 0.0.0.0:80
.111.111.111.111
sin puerto se convierte en 111.111.111.111:80
.8888
sin dirección IP se convierte en 0.0.0.0:8888
.0.0.0.0
como su dirección IP (para coincidir con cualquier interfaz), no se seleccionará si hay bloques coincidentes que enumeran una dirección IP específica. En todo caso, el puerto debe coincidir con exactitud.server_name
de cada bloque de servidores.Es importante entender que Nginx solo evaluará la directiva server_name
cuando necesite distinguir entre bloques de servidores que coinciden con el mismo nivel de especificidad en la directiva listen
. Por ejemplo, si example.com
está alojado en el puerto 80
de 192.168.1.10
, una solicitud para example.com
siempre será atendida por el primer bloque de este ejemplo, a pesar de la directiva server_name
en el segundo bloque.
server {
listen 192.168.1.10;
. . .
}
server {
listen 80;
server_name example.com;
. . .
}
En caso de que más de un bloque de servidor coincida con la misma especificidad, el siguiente paso es verificar la directiva server_name
.
Luego, para evaluar más a fondo las solicitudes que tienen directivas listen
igualmente específicas, Nginx verifica el encabezado “Host” de la solicitud. Ese valor contiene el dominio o la dirección IP que el cliente estaba intentando alcanzar.
Nginx intenta encontrar la mejor coincidencia para el valor que encuentra al ver la directiva server_name
dentro de cada uno de los bloques de servidores que aún son candidatos a selección. Nginx lo evalúa usando la siguiente formula:
server_name
que coincida con el valor en el encabezado “Host” de la solicitud de manera exacta. Si lo encuentra, ese bloque asociado se utilizará para atender la solicitud. Si se encuentran varias coincidencias exactas, se utiliza la primera coincidencia.server_name
que coincida usando un comodín inicial (indicado por un *
al principio del nombre en la configuración). Si lo encuentra, ese bloque se utilizará para atender la solicitud. Si se encuentran varias coincidencias, la coincidencia más larga se utilizará para atender la solicitud.server_name
que coincida usando un comodín final (indicado por un nombre de servidor que termina con un *
en la configuración). Si lo encuentra, ese bloque se utilizará para atender la solicitud. Si se encuentran varias coincidencias, la coincidencia más larga se utilizará para atender la solicitud.server_name
usando expresiones regulares (indicadas por un ~
antes del nombre). El primer server_name
con una expresión regular que coincida con el encabezado “Host” se utilizará para atender la solicitud.Cada combinación de dirección IP/puerto tiene un bloque de servidor predeterminado que se utilizará cuando no se pueda determinar un curso de acción con los métodos anteriores. En el caso de una combinación de dirección IP y puerto, será el primer bloque de la configuración o el bloque que contiene la opción default_server
como parte de la directiva listen
(que anularía el primer algoritmo encontrado). Solo puede haber una declaración default_server
por cada combinación de dirección IP y puerto.
Si se define un server_name
que coincida exactamente con el valor de encabezado “Host”, se selecciona ese bloque de servidor para procesar la solicitud.
En este ejemplo, si el encabezado “Host” de la solicitud se estableció en “host1.example.com”, se seleccionaría el segundo servidor:
server {
listen 80;
server_name *.example.com;
. . .
}
server {
listen 80;
server_name host1.example.com;
. . .
}
Si no se encuentra ninguna coincidencia exacta, Nginx comprueba entonces si hay un server_name
con un comodín inicial que coincida. Se seleccionará la coincidencia más larga que comience con un comodín para satisfacer la solicitud.
En este ejemplo, si la solicitud tuviera un encabezado “Host” de “www.example.org”, se seleccionaría el segundo bloque de servidor:
server {
listen 80;
server_name www.example.*;
. . .
}
server {
listen 80;
server_name *.example.org;
. . .
}
server {
listen 80;
server_name *.org;
. . .
}
Si no se encuentra ninguna coincidencia con un comodín inicial, Nginx verá si existe una coincidencia usando un comodín al final de la expresión. En este punto, se seleccionará la coincidencia más larga que termine con un comodín para atender la solicitud.
Por ejemplo, si la solicitud tiene un encabezado “Host” establecido en “www.example.com”, se seleccionará el tercer bloque de servidor:
server {
listen 80;
server_name host1.example.com;
. . .
}
server {
listen 80;
server_name example.com;
. . .
}
server {
listen 80;
server_name www.example.*;
. . .
}
Si no se encuentran coincidencias con los comodines, Nginx pasará a intentar coincidir con las directivas server_name
que utilicen expresiones regulares. Se seleccionará la primera expresión regular que coincida para responder a la solicitud.
Por ejemplo, si el encabezado “Host” de la solicitud está configurado en “www.example.com”, se seleccionará el segundo bloque de servidor para satisfacer la solicitud:
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$;
. . .
}
Si ninguno de los pasos anteriores puede satisfacer la solicitud, la solicitud se pasará al servidor predeterminado para la dirección IP y el puerto que coincidan.
De forma similar al proceso que utiliza Nginx para seleccionar el bloque del servidor que procesará una solicitud, Nginx también tiene un algoritmo establecido para decidir qué bloque de ubicación dentro del servidor se utilizará para gestionar las solicitudes.
Antes de ver cómo Nginx decide qué bloque de ubicación utilizar para gestionar las solicitudes, repasemos parte de la sintaxis que se podría encontrar en las definiciones de los bloques de ubicación. Los bloques de ubicación se encuentran dentro de los bloques de servidor (u otros bloques de ubicación) y se utilizan para decidir cómo procesar la URI de la solicitud (la parte de la solicitud que viene después del nombre de dominio o la dirección IP/puerto).
Los bloques de ubicación generalmente tienen la siguiente forma:
location optional_modifier location_match {
. . .
}
location_match
que aparece arriba define contra qué debe comprobar Nginx la URI de la solicitud. La existencia o la inexistencia del modificador en el ejemplo anterior afecta a la forma en que Nginx intenta hacer coincidir el bloque de ubicación. Los modificadores que se muestran abajo harán que el bloque de ubicación asociado se interprete de la siguiente manera:
=
: si se utiliza un signo igual, este bloque se considerará coincidente si el URI de la solicitud coincide exactamente con la ubicación indicada.~
: si hay una tilde de la eñe, esta ubicación se interpretará como una coincidencia de expresión regular que distingue entre mayúsculas y minúsculas.~*
: si se utiliza un modificador de tilde de la eñe y asterisco, el bloque de ubicación se interpretará como una coincidencia de expresión regular que no distingue entre mayúsculas y minúsculas.^~
: si hay un modificador de acento circunflejo y tilde de la eñe, y si este bloque se selecciona como la mejor coincidencia de expresión no regular, no se realizará la coincidencia de expresión regular.Como ejemplo de concordancia de prefijos, se puede seleccionar el siguiente bloque de ubicación para responder a los URI de solicitud que tienen el aspecto /site
, /site/page1/index.html
o /site/index.html
:
location /site {
. . .
}
Para una demostración de la coincidencia exacta del URI de la solicitud, este bloque siempre se utilizará para responder a un URI de solicitud que tenga el aspecto /page1
. No se utilizará para responder a un URI de solicitud /page1/index.html
. Tenga en cuenta que, si se selecciona este bloque y la solicitud se cumple usando una página de índice, se realizará un redireccionamiento interno a otra ubicación que será la que realmente gestione la solicitud:
location = /page1 {
. . .
}
Como ejemplo de una ubicación que debe interpretarse como una expresión regular que distingue entre mayúsculas y minúsculas, este bloque puede usarse para gestionar las solicitudes de /tortoise.jpg
, pero no para /FLOWER.PNG
:
location ~ \.(jpe?g|png|gif|ico)$ {
. . .
}
A continuación, se muestra un bloque que permitiría una coincidencia sin distinción ente mayúsculas y minúsculas similar al que se mostró anteriormente. Este bloque podría gestionar /tortoise.jpg
y /FLOWER.PNG
:
location ~* \.(jpe?g|png|gif|ico)$ {
. . .
}
Por último, este bloque evitaría que se produjera una coincidencia de expresión regular si se determina que es la mejor coincidencia de expresión no regular. Podría gestionar las solicitudes de /costumes/ninja.html
:
location ^~ /costumes {
. . .
}
Como ve, los modificadores indican cómo debe interpretarse el bloque de ubicación. Sin embargo, esto no nos indica el algoritmo que utiliza Nginx para decidir a qué bloque de ubicación enviar la solicitud. Lo repasaremos a continuación.
Nginx elige la ubicación que se utilizará para atender una solicitud de forma similar a cómo selecciona un bloque de servidor. Se ejecuta a través de un proceso que determina el mejor bloque de ubicación para cualquier solicitud. Entender este proceso es un requisito crucial para poder configurar Nginx de forma fiable y precisa.
Teniendo en cuenta los tipos de declaraciones de ubicación que hemos descrito anteriormente, Nginx evalúa los posibles contextos de ubicación comparando el URI de solicitud con cada una de las ubicaciones. Lo hace mediante el siguiente algoritmo:
=
y que coincida con el URI de la solicitud de manera exacta, este bloque de ubicación se selecciona inmediatamente para atender la solicitud.=
), Nginx pasa a evaluar los prefijos no exactos. Descubre la ubicación del prefijo más largo que coincide con el URI de la solicitud dada que luego evalúa de la siguiente manera:
^~
, Nginx finalizará inmediatamente su búsqueda y seleccionará esta ubicación para atender la solicitud.^~
, Nginx almacena la coincidencia de momento para poder cambiar el enfoque de la búsqueda.Es importante entender que, de manera predeterminada, Nginx atenderá las coincidencias de expresiones regulares con mayor preferencia en comparación con las coincidencias de prefijos. Sin embargo, primero evalúa las ubicaciones de prefijos, lo que permite al administrador anular esta tendencia especificando las ubicaciones usando los modificadores =
y ^~
.
También es importante tener en cuenta que, aunque las ubicaciones de prefijos generalmente se seleccionan según la coincidencia más larga y específica, la evaluación de la expresión regular se detiene cuando se encuentra la primera ubicación que coincida. Eso significa que el posicionamiento dentro de la configuración tiene amplias implicaciones para las ubicaciones de expresiones regulares.
Por último, es importante entender que las coincidencias de expresiones regulares dentro de la coincidencia del prefijo más largo “saltarán la línea” cuando Nginx evalúe las ubicaciones de regex. Estas se evaluarán en orden, antes de que se consideren las demás coincidencias de expresiones regulares. Maxim Dounin, un desarrollador de Nginx increíblemente atento, explica en esta publicación esta parte del algoritmo de selección.
En general, cuando se selecciona un bloque de ubicación para atender una solicitud, la solicitud se gestiona completamente dentro de ese contexto a partir de ese momento. Solo la ubicación seleccionada y las directivas heredadas determinan cómo se procesa la solicitud, sin interferencia de los bloques de ubicación hermanos.
Aunque esta es una regla general que le permitirá diseñar sus bloques de ubicación de una manera predecible, es importante darse cuenta de que, a veces, una nueva búsqueda de ubicación se activa por ciertas directivas dentro de la ubicación seleccionada. Las excepciones a la regla “solo un bloque de ubicación” pueden tener implicaciones sobre cómo se atiende realmente la solicitud y pueden no coincidir con las expectativas que tenía al diseñar sus bloques de ubicación.
Algunas directivas que pueden dar como resultado este tipo de redireccionamiento interno son:
Las repasaremos brevemente.
La directiva index
siempre conduce a un redireccionamiento interno si se utiliza para gestionar la solicitud. Las coincidencias de ubicación exactas se utilizan a menudo para acelerar el proceso de selección, terminando inmediatamente la ejecución del algoritmo. Sin embargo, si realiza una coincidencia de ubicación exacta que sea un directorio, hay una buena probabilidad de que la solicitud sea redirigida a una ubicación diferente para el procesamiento real.
En este ejemplo, la primera ubicación coincide con un URI de solicitud de /exact
, pero, para gestionar la solicitud, la directiva index
heredada por el bloque inicia un redireccionamiento interno al segundo bloque:
index index.html;
location = /exact {
. . .
}
location / {
. . .
}
En el caso anterior, si realmente necesita que la ejecución permanezca en el primer bloque, tendrá que encontrar un método diferente para satisfacer la solicitud al directorio. Por ejemplo, podría establecer un index
no válido para ese bloque y activar autoindex
:
location = /exact {
index nothing_will_match;
autoindex on;
}
location / {
. . .
}
Esta es una forma de evitar que un index
cambie de contexto, pero probablemente no sea útil para la mayoría de las configuraciones. Generalmente, una coincidencia exacta en directorios puede ser útil para acciones como reescribir la solicitud (lo que también genera una nueva búsqueda de ubicación).
Otro caso en que se puede reevaluar la ubicación del procesamiento es con la directiva try_files
. Esa directiva le indica a Nginx que busque la existencia de un conjunto determinado de archivos o directorios. El último parámetro puede ser un URI al que Nginx realizará un redireccionamiento interno.
Analice la siguiente configuración:
root /var/www/main;
location / {
try_files $uri $uri.html $uri/ /fallback/index.html;
}
location /fallback {
root /var/www/another;
}
En el ejemplo anterior, si se realiza una solicitud para /blahblah
, la primera ubicación obtendrá inicialmente la solicitud. Intentará encontrar un archivo llamado blahblah
en el directorio /var/www/main
. Si no puede encontrar ninguno, procederá a buscar un archivo llamado blahblah.html
. Luego, intentará buscar un directorio llamado blahblah/
dentro del directorio /var/www/main
. Si todos esos intentos fallan, se redirigirá a /fallback/index.html
. Eso activará otra búsqueda de ubicación que el segundo bloque de ubicación capturará. Y atenderá el archivo /var/www/another/fallback/index.html
.
Otra directiva que puede pasar el bloque de ubicación es la directiva rewrite
. Cuando utiliza el último
parámetro con la directiva rewrite
o cuando no utiliza ningún parámetro, Nginx buscará una nueva ubicación que coincida según los resultados de la reescritura.
Por ejemplo, si modificamos el último ejemplo para incluir una reescritura, podemos ver que la solicitud a veces se pasa directamente a la segunda ubicación sin depender de la directiva 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;
}
En el ejemplo de arriba, el primer bloque de ubicación gestionará inicialmente una solicitud de /rewriteme/hello
. Se reescribirá a /hello
y se buscará una ubicación. En este caso, volverá a coincidir con la primera ubicación y se procesará mediante try_files
de manera habitual, probablemente regresando a /fallback/index.html
si no se encuentra nada (usando el redireccionamiento interno de try_files
que mencionamos antes).
Sin embargo, si se realiza una solicitud para /rewriteme/fallback/hello
, el primer bloque volverá a coincidir. Se aplicará la reescritura de nuevo, dando como resultado /fallback/hello
esta vez. La solicitud se atenderá desde el segundo bloque de ubicación.
Algo similar sucede con la directiva return
cuando se envían los códigos de estado 301
o 302
. La diferencia en este caso es que da como resultado una solicitud completamente nueva en forma de un redireccionamiento visible desde el exterior. Eso mismo puede suceder con la directiva rewrite
cuando se utilizan los indicadores redirect
o permanent
. Sin embargo, estas búsquedas de ubicación no deberían ser inesperadas, ya que los redireccionamientos visibles externamente siempre dan como resultado una nueva solicitud.
La directiva error_page
puede dar como resultado un redireccionamiento interno similar al que se creó con try_files
. Esa directiva se utiliza para definir lo que debe suceder cuando se encuentran ciertos códigos de estado. Esto probablemente nunca se ejecutará si se establece try_files
, ya que esa directiva maneja todo el ciclo de vida de una solicitud.
Analice este ejemplo:
root /var/www/main;
location / {
error_page 404 /another/whoops.html;
}
location /another {
root /var/www;
}
Todas las solicitudes (aparte de las que comienzan con /another
) se gestionarán mediante el primer bloque, que atenderá archivos desde /var/www/main
. Sin embargo, si no se encuentra un archivo (un estado 404), se producirá un redireccionamiento interno a /another/whoops.html
, lo que llevará a una nueva búsqueda de ubicación que finalmente aterrizará en el segundo bloque. Este archivo se atenderá desde /var/www/another/whoops.html
.
Como se puede ver, entender las circunstancias en que Nginx activa una nueva búsqueda de ubicación puede ayudar a predecir el comportamiento que habrá cuando se hagan solicitudes.
Entender las formas en que Nginx procesa las solicitudes de los clientes puede hacer que su trabajo como administrador sea mucho más fácil. Podrá saber qué bloque de servidor seleccionará Nginx según cada solicitud del cliente. También podrá saber cómo se seleccionará el bloque de ubicación según el URI de la solicitud. En general, saber la forma en que Nginx selecciona los diferentes bloques le permitirá rastrear los contextos que Nginx aplicará para atender cada solicitud.
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!