7.2.2.2.2. Dominios virtuales

Es común que un mismo servidor web sirva páginas cuyo nombre de sitio es distinto. Por ejemplo, un sitio puede ser sitio1.dominio.org y otro distinto sitio2.dominio.org. Sin embargo, ambos están alojados en nuestro servidor web.

Para lograr tal, debemos utilizar tres sentencias: server, listen y server_name. Por ejemplo:

# cat /etc/nginx/sites-available/sitio1
server {
   listen  80;
   server_name  sitio1.dominio.org;

   try_files $uri $uri/ =404;
   root /srv/www/sitio1;
}
# cat /etc/nginx/sites-available/sitio2
server {
   listen  80;
   server_name  sitio2.dominio.org;

   try_files $uri $uri/ =404;
   root /srv/www/sitio2;
}

Por lo general, cada sentencia server se corresponde con un dominio virtual distinto, y cada dominio se coloca en un fichero distinto. Además, para que estén habilitados, los ficheros tienen que estar enlazados en sites-enabled por lo que es necesario:

# cd /etc/nginx/sites-enabled
# ln -fs ../sites-available/sitio1
# ln -fs ../sites-available/sitio2

7.2.2.2.2.1. server_name

No obstante lo anterior, las cosas pueden complicarse hasta el punto de que server_name tiene un apartado dedicado en exclusiva a su explicación[1]. De hecho, server_name no tiene por qué contener un nombre sin más, sino que puede contener:

  • Un nombre, como sitio1.dominio.org.

  • Un nombre con comodín al comienzo (p.e. *.dominio.org) o al final (p.e. www.dominio.*).

  • Una expresión regular (con sintaxis PCRE), en cuyo caso debe comenzarse la expresión con una virgulilla, como ~^www.([^.]+.[^.]+)$.

  • Una combinación cualquiera de las tres posibilidades anteriores:

    server_name   dominio.org
                *.dominio.org;
    

Nota

La documentación nos advierte de que el nombre .dominio.org se trata de forma especial y equivale a la combinación de nombres usada justamente encima de esta nota:

server_name  .dominio.org;

Las expresiones regulares, además de permitir definir patrones bastantes complicados de coincidencia, permiten almacenar parte del nombre en una variable y usarlo luego en la configuración. Por ejemplo:

server {
   listen  80;
   server_name ~^([^.]+)\..*;

   root /srv/www/$1;
   try_files $uri $uri/ =404;
}

Advertencia

Cuando una expresión regular contiene llaves de apertura o cierre, o punto y coma es preciso encerrarla entre comillas dobles.

no sólo eso, sino que se puede usar la captura con nombres para facilitar la lectura de la configuración:

server {
   listen  80;
   server_name ~^(?P<vhost>[^.]+)\..*;

   root /srv/www/$vhost;
   try_files $uri $uri/ =404;
}

Nota

Como valor se puede usar también una ip o una ip con comodín:

server_name 172.22.0.2 192.168.*;

Nota

Hay algunas apuntes en la documentación oficial sobre la forma en que nginx procesa y compara el campo Host: con los valores de la directiva y nos explica que, obviamente, es más eficiente la comparación de nombres exactos y luego de nombres con comodines que la comparación con expresiones regulares. Además, nos advierte de que, si a un servidor se accede mayoritariamente con un nombre, es mejor declarar explícitamente ese nombre. Por tanto es mejor desde el punto de vista del rendimiento, esto:

server_name www.dominio.org  dominio.org *.dominio.org;

que esto otro:

server_name .dominio.org;

7.2.2.2.2.2. Selección del dominio virtual

Conocido cómo escribir la directiva server_name, lo interesante es saber cuál es el algoritmo que sigue nginx para seleccionar cuál es el bloque server que usará para responder a una petición. El algoritmo es el siguiente:

  1. Se seleccionan aquellos bloques cuya directiva listen esté en consonancia con la petición.

  2. Para los bloques anteriores, se escoge aquel en que el valor de la directiva server_name concuerde con el campo Host: de la petición

    • Si son varios los bloques, entonces la precedencia en la concordancia con server_name es la siguiente:

      1. Nombre exacto.

      2. Nombre con comodín al principio. Cuanto más largo, más precedente.

      3. Nombre con comodín al final. Cuanto más largo, más precedente.

      4. Expresión regular. Si hay concordancia con varias expresiones regulares se coge el bloque server concordante que aparece en primer lugar dentro del fichero[2].

    • Si no hay bloque seleccionado por falta de concordancia, se toma aquel que incluya el parámetro default_server en su sentencia listen:

      listen  80 default_server;
      

      y, si ningún bloque tenía una sentencia listen que incluyera el parámetro, se toma el primer server[2][3].

Notas al pie