0xf41f800000 for PSP TMR
table of contents

Qué es Nginx y cómo funciona

Actualizado el

a las

Nginx es un servidor web, proxy inverso, balanceador de carga, proxy TCP/UDP y proxy para correos electrónicos escrito en el lenguaje de programación C por Igor Sysoev. Su primera versión fue lanzada en 2004 como una solución al problema llamado C10K.

Logo del servidor web, proxy inverso y balanceador de carga; Nginx

Publicado el

a las

Qué es Nginx

Nginx es un servidor web diseñado para tareas de alto rendimiento, pensado para incrementar la seguridad y reducir la carga del sistema al balancearla entre distintos servidores según la carga de cada uno al momento de procesar las solicitudes del cliente. 

El incipiente crecimiento de la popularidad de Internet en la primera parte de los años 2000 dejó en evidencia un problema; el cada vez peor rendimiento al procesar una enorme cantidad de conexiones concurrentes.

En 2002 y a raíz del problema C10K, nació la idea que en 2004 se materializó como Nginx. Un servidor web que evolucionó a balanceador de carga y proxy inverso con reputación de robustez, eficiencia y rendimiento.

Su arquitectura

A diferencia de otros servidores donde cada nueva conexión se gestiona con un nuevo proceso o hilo que bloquea la red o las operaciones de escritura, la arquitectura de Nginx se compone de un proceso principal llamado master process  y uno o varios worker processes

  • El master process se encarga de todas las operaciones con privilegios como leer las configuraciones, vincular puertos o gestionar y supervisar a los worker processes.
  • Un worker process se encarga de gestionar todas las peticiones. Cuando hay más de uno definidos Nginx las distribuye basándose en eventos y mecanismos del sistema operativo anfitrión.
nginx
#En Windows, Nginx solo puede utilizar un worker process.
#Además, la funcionalidad de UDP no está soportada.

Syntax: worker_processes number | auto;  
Default: worker_processes 1; 
Context: main;

De esta manera Nginx evita crear un nuevo proceso por cada nueva conexión, en su lugar, cada uno de los worker process escucha a través de un socket compartido. Dentro de cada worker process se ejecuta un bucle de ejecución que maneja las conexiones de manera asíncrona.

Esta arquitectura es más eficiente en términos de gestión de recursos, especialmente si se compara con la arquitectura de otros servidores, donde cada nueva conexión crea un nuevo proceso o hilo, se prepara el entorno en tiempo de ejecución, y consume recursos del sistema que pueden ser aprovechados en otras tareas.

Lo anterior también explica la creciente popularidad de Nginx.

Proxy Inverso

Como Proxy InversoNginx actúa como intermediario, se sitúa delante de los servidores principales que pueden o no estar en otras máquinas o VPS.

De esta forma, cuando un cliente realiza una solicitud a un sitio web, Nginx recibe la solicitud y la envía al servidor correspondiente. Esto incrementa la seguridad, ya que el servidor de destino puede escuchar en un puerto restringido solo accesible para Nginx.

Además, al utilizar un proxy inverso el servidor final puede ocultar su dirección IP real, evitando que los clientes accedan a él directamente, esto mejora la privacidad y la protección contra ataques ya que reduce las opciones de los atacantes.

nginx
server {

	location / {

		proxy_pass http://66.249.93.40:3000;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;

	}

}

Un proxy inverso es útil por varias razones, entre ellas, la gestión de registros de actividad, eventos, solicitudes e incluso la mitigación de ataques, pudiendo compartir archivos de configuración entre sí.

Un sitio web puede contar con un dominio principal, por ejemplo daniloarancibia.es, y este a su vez con un subdominio llamado workspace.daniloarancibia.es, tanto el primero como el segundo cuentan con su propio archivo de registro de actividad, pero comparten configuraciones como bloqueos por IP, agente de usuario o excepciones de registros.

nginx
	#Lo ideal es agrupar bloqueos de rutas, user-agents, entre otros,
	#en archivos separados que pueden ser utilizados en otros virtual hosts.
	include /etc/nginx/conf.d/blockemptyuseragent.conf;
	include /etc/nginx/conf.d/blockroutesglobally.conf;

Ambos, el dominio principal y el subdominio están detrás de un proxy inverso que reenvía las peticiones a los servidores donde están alojadas las aplicaciones.

Balanceador de Carga

Como balanceador de carga Nginx gestiona el destino de las solicitudes entrantes. El concepto es parcialmente similar al de un proxy inverso, pero con matices.

Cuando intercepta una solicitud, utiliza un algoritmo llamado Round Robin para decidir a qué servidor reenviarla. También cuenta con otros como el Least Connections, pero el primero es la opción por defecto. La lógica de este algoritmo es sencilla. Consiste en distribuir las solicitudes de manera equitativa y circular.

Algoritmo Round Robin

Round Robin es el algoritmo que utiliza Nginx para procesar solicitudes de forma equitativa y circular. Es necesario aclarar que el algoritmo utilizado por Nginx no es el mismo que se utiliza en sistemas operativos, el Round Robin Scheduling, cuya diferencia no quedará sin explicación.

La lógica del algoritmo es sencilla y de hecho, no es una funcionalidad necesaria en la mayoría de los casos mientras el rendimiento no se vea afectado por el tráfico.

El siguiente bloque de código extraído de la documentación de Nginx es un ejemplo sobre como funciona Round Robin.

nginx
http {
    upstream myapp1 {
        server srv1.example.com;
        server srv2.example.com;
        server srv3.example.com;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://myapp1;
        }
    }
}

El ejemplo anterior cuenta con 3 servidores que alojan la instancia de una misma aplicación.

Cuando Nginx intercepta las peticiones de los usuarios, por ejemplo, 3 solicitudes, se distribuyen equitativamente entre los 3 servidores.

La primera solicitud va al servidor 1, la segunda al servidor 2, la tercera al 3 y al entrar una cuarta solicitud el ciclo comienza otra vez, es decir el servidor 1 gestionará esa 4ª solicitud.

Round Robin Scheduling:

En el contexto de sistemas operativos se introduce un concepto matemático: los quantums. Estos hacen referencia al tiempo asignado a los procesos en cola.

Cada uno cuenta con el mismo tiempo para utilizar el procesador y, una vez se agota, si el proceso no se ha completado regresa al final de la cola para dar paso al siguiente. La secuencia se repite hasta que cada proceso se ha completado.

Los quantums pueden variar de acuerdo a la configuración del algoritmo.

Un quantum demasiado largo puede dar la sensación de lentitud mientras que uno demasiado corto puede sobrecargar el sistema con cambios de contexto demasiado frecuentes.

Esa es la diferencia entre el algoritmo Round Robin que utiliza Nginx y la versión Round Robin Scheduling.

Optimización y rendimiento

Al visitar un sitio web, generalmente y de forma automática, el navegador envía múltiples solicitudes al servidor para descargar los recursos de la página. Cada una de ellas debe ser resuelta antes de dar paso a la siguiente, y en consecuencia, cada solicitud crea una nueva conexión y la cierra al ser resuelta. 

Lo anterior es ineficiente y es más evidente en conexiones lentas. Para resolver este problema Nginx utiliza un método llamado multiplexación.

La multiplexación permite transportar múltiples solicitudes en una sola conexión y responder con un streaming de datos utilizando HTTP/2, sin necesidad de resolver una solicitud a la vez y por orden de llegada, que es como funciona HTTP/1.1 y es la principal causa del head-of-line-blocking.

HTTP/2

Algunas versiones de Nginx cuentan con el módulo HTTP/2, se trata de una versión optimizada del protocolo de transferencia HTTP. Con ello introduce una serie de mejoras que incrementan el rendimiento en comparación a versiones anteriores. Sin embargo, como lo explica la IETF, HTTP/2 no hace que la versión HTTP/1.1 sea obsoleta, y es más bien opcional y recomendada.

Para enviar múltiples solicitudes en una sola conexión TCP, HTTP/1.1 utiliza un método llamado request pipelining, este método tiene un problema subyacente, el head-of-line-blocking.

El head-of-line-blocking pasa cuando un cliente envía múltiples solicitudes a un servidor que utiliza HTTP/1.1, aunque todas viajan a través de una sola conexión, las respuestas del servidor deben ser devueltas en el mismo orden de llegada (FIFO).

Esto quiere decir que, si un cliente envía 7 solicitudes, el servidor puede procesarlas paralelamente en caso que cuente con un procesador multithreading, a pesar de ello y aunque la mayoría de solicitudes estén resueltas, el servidor no puede enviar la respuesta al cliente mientras la solicitud 3 no lo esté.

HTTP/2 propone un uso más eficiente de los recursos de red, para ello se basa en mecanismos de streaming y compresión de cabeceras. En una conexión HTTP/2 el cliente y el servidor crean un canal de intercambio bidireccional, por cada solicitud se crea un stream con identificador único y pueden coexistir múltiples streams concurrentes.

En el contexto de HTTP/2, un stream es un flujo de frames y estos últimos a su vez son pequeños trozos de datos. Lo anterior significa que en una conexión HTTP/2 con múltiples streams concurrentes, el servidor envía respuestas parciales por cada solicitud. De esta forma HTTP/2 resuelve el head-of-line-blocking, porque el servidor no tiene que esperar a que cada respuesta esté resuelta, sino que envía pequeños trozos de cada una según disponibilidad.

Compresión de archivos

Nginx cuenta con dos módulos para la compresión de archivos, Gzip y Brotli, ambos deshabilitados por defecto, sin embargo cada uno cuenta con sus respectivas directivas para habilitarlos.

Es importante saber que habilitar Gzip resulta más sencillo que Brotli, ya que este último en Nginx Plus, la versión de pago, está compilado por defecto. En cambio en la versión open source no lo está, lo que se traduce en tener que compilar el módulo manualmente y de forma personalizada.

El siguiente bloque de código muestra la sintaxis para activar Gzip, seguido de su estado por defecto y por último el contexto donde dicha configuración es aplicable. 

nginx
Syntax:	gzip on | off;
Default:	
gzip off;
Context:	http, server, location, if in location

Los virtual-hosts de Nginx utilizan la directiva location que, a grosso modo, sirve para interceptar solicitudes que coinciden con el patrón de la directiva, un ejemplo sería location /api/. Cualquier solicitud que coincida con dicho patrón será interceptada por esa directiva y resuelta según la configuración que contenga el bloque.

El siguiente ejemplo muestra como procesar las solicitudes de location /api/ y a su vez habilitar la compresión y aplicar otras configuraciones que puedan resultar útiles.

nginx
	location /api/ {

		gzip on;
		gzip_comp_level 5;
		gzip_min_length 51200;

		proxy_pass http://66.249.93.40:3000;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;

	}

Estos mecanismos de compresión ayudan a que Nginx pueda rendir mejor al comprimir los recursos solicitados por el cliente, ya que, si la cache está habilitada en Nginx, los puede mantener en cache sin la necesidad de leer o comprimir en cada solicitud.

La posibilidad de habilitar o deshabilitar estos módulos a nivel granular, como en el caso de la directiva location, ayuda mitigar ciertas incompatibilidades.

Por ejemplo con Next JS, que cuenta con su propio sistema de compresión de recursos, hacer que Brotli funcione requiere configuraciones adicionales en el framework. Sin embargo, al poder deshabilitar el módulo en la directiva location, es posible seguir utilizando Brotli en otras rutas donde sea necesaria la compresión de archivos. 

Seguridad y monitoreo

La seguridad en Nginx no se compone de un módulo en específico, sino de una serie de prácticas y combinación de configuraciones para garantizar un sistema robusto, securizado y a prueba de fallos.

Un ejemplo de ello es cuando funciona como proxy inverso, si los sitios web que sirve están alojados en otros servidores físicos, el de Nginx puede ser accesible desde la red mientras el que aloja la aplicación permanece completamente restringido y solo accesible desde la IP del servidor de Nginx.

Esto es una capa de seguridad adicional, pero no la única y tampoco es infalible; si un atacante vulnera el servidor donde está Nginx, tendrá acceso a la  dirección del servidor donde está alojada la aplicación y podrá atacar a través del proxy o acceder directamente si el proxy tiene las claves SSH almacenadas.

Todo lo anterior por sí solo no es suficiente, también es necesario utilizar certificados SSL, restringir el acceso al servidor y revisar de forma habitual los registros de actividad (logs).  

Rate limiting

Para aplicar el rate limiting, Nginx incluye el módulo ngx_http_limit_req_module, está pensado para limitar la cantidad de solicitudes que un cliente puede ejecutar en un intervalo de tiempo establecido por el servidor, para ello, se basa en el algoritmo "leaky bucket". Este módulo se utiliza para mitigar ataques de tipo DDoS y cuenta con 5 directivas de configuración:

  • limit_req_zone: Se utiliza para configurar la clave, generalmente se suele utilizar la variable binary_remote_addr, que es una representación binaria de la IP del cliente, la zona y el pico máximo de solicitudes. Esta directiva solo se puede utilizar en el bloque http
  • limit_req: Dado un contexto, por ejemplo location, se usa para especificar qué zona debe utilizar Nginx. Es posible definir múltiples zonas. 
  • limit_req_dry_run: Ejecuta las configuraciones de limit_req en modo de prueba, es decir, las configuraciones se ejecutarán sin aplicar un límite real, pero simulará la configuración completa.  
  • limit_req_log_level: Sirve para especificar el nivel de los registros cuando la cantidad de solicitudes excede el límite establecido, los niveles son: info, notice, warn y error.
  • limit_req_status: Se utiliza para configurar el código de estado de la respuesta del servidor, un ejemplo es que, en lugar de devolver un 429, que corresponde al código de estado para el rate limiting, se puede devolver un código 500.

En la descripción de limit_req_status, se menciona la posibilidad de devolver un código de estado 500 en lugar del 429, la razón para devolver un código de estado distinto son los bots.

En la mayoría de situaciones los ataques son ejecutados por bots que escanean la red en busca de sitios web con vulnerabilidades de configuración.

Estos bots se basan encódigos de estado para ejecutar el ataque, y aunque enviar un código de estado distinto no garantiza evitar el ataque, sí permite reducir la información que se expone sobre el servidor. El siguiente fragmento de código muestra un ejemplo de como configurar el rate limiting en Nginx:

nginx
http {

	# limit requests
	limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;
	limit_req_zone $binary_remote_addr zone=req_zone_wl:10m rate=15r/s;
	
	# otras configuraciones...
	include /etc/nginx/sites-enabled/*;
	
}

El bloque anterior muestra dos zonas cada una con un límite distinto y, el siguiente muestra un bloque location de un virtual host que aplica los rate limits para distintos bloques location.

nginx
server {

		location / {

			limit_req zone=A burst=20 nodelay;
			limit_req_log_level info;
			limit_req_status 500;

			proxy_pass http://66.249.93.40:3000;
			proxy_set_header Host $host;
			proxy_set_header X-Real-IP $remote_addr;
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
			proxy_set_header X-Forwarded-Proto $scheme;

		}

		location /login {

			limit_req zone=B burst=20 nodelay;
			limit_req_log_level error;
			limit_req_status 500;

			proxy_pass http://66.249.93.40:3001;
			proxy_set_header Host $host;
			proxy_set_header X-Real-IP $remote_addr;
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
			proxy_set_header X-Forwarded-Proto $scheme;

		}
		
}

Certificados SSL

Nginx ofrece soporte para conexiones seguras a través del módulo ngx_http_ssl_module. Entre las directivas de este módulo están ssl_certificate, ssl_dhparam y ssl_certificate_key, entre otras que controlan el comportamiento de las conexiones SSL/TLS.

Existen herramientas gratuitas y de código abierto que automatizan la obtención, instalación y renovación de certificados SSL.

Una de ellas es Certbot, un proyecto de la Electronic Frontier Foundation (EFF), que automatiza todo el proceso de generar certificados SSL usando Let's Encrypt. Certbot configura los certificados generados en los virtual hosts y los renueva automáticamente a través de un cron job en servidores GNU/Linux.

Permisos de acceso

Nginx cuenta con el módulo ngx_http_access_module para gestionar el acceso.

Este módulo cuenta con dos directivas,  deny y allow, el siguiente bloque de código muestra el contexto donde las directivas son aplicables. 

nginx
Syntax:	allow address | CIDR | unix: | all;
Default:	—
Context:	http, server, location, limit_except

Syntax:	deny address | CIDR | unix: | all;
Default:	—
Context:	http, server, location, limit_except

Con este módulo es posible restringir el acceso a direcciones IP específicas o bien a un bloque de IPs.

Por ejemplo, en el siguiente bloque de código el administrador deniega el acceso a la IP 192.168.1.1, pero permite el acceso al resto con 192.168.1.0/24, sin embargo, al final del bloque configura deny  all, esta última regla sobrescribe al resto porque las reglas se leen de arriba hacia abajo, lo que significa que el acceso está restringido en general.

nginx
location / {
    deny  192.168.1.1;
    allow 192.168.1.0/24;
    allow 10.1.1.0/16;
    allow 2001:0db8::/32;
    deny  all;
}

Registros de actividad (Logs)

Para el registro de actividad, Nginx cuenta con el módulo ngx_http_log_module, este módulo permite configurar el formato, la compresión de los registros y donde van a ser escritos.

Sin embargo, para registrar los errores, tiene una directiva que forma parte del núcleo y no depende directamente de este módulo, se trata de la directiva error_log, que, como bien lo dice su nombre, sirve para registrar los fallos a nivel de sistema y virtual hosts.

nginx
	# Logging Settings
	access_log /var/log/nginx/daniloarancibia.es/access.log combined if=$loggable;
	error_log /var/log/nginx/daniloarancibia.es/error.log;

El bloque anterior muestra un ejemplo de las directivas access_log y error_log, en el primero se trata de la configuración por defecto para access_log. Combined le dice a Nginx que debe usar el formato por defecto, mientras que if=$loggable; le dice que solo registre la actividad si se cumple dicha condición.

En este caso la condición de loggable se encuentra en el archivo de configuración global de Nginx, nginx.conf

nginx
	map $remote_addr $loggable { 
         
	default 1;

	} 

El módulo ngx_http_map_module permite al administrador declarar variables que dependen del valor de otras variables, para ello se utiliza su directiva map. Dicho de otra forma, en el bloque anterior loggable depende de remote_addr que no es más que la dirección IPV4 del cliente, o si cuenta con ella, la dirección IPV6 y por defecto registra todos los accesos.

La variable remote_addr también forma parte del núcleo de Nginx y es accesible en todos los archivos de configuración y virtual hosts.

Si el administrador necesita bloquear los registros de actividad vinculados a su IP, sería suficiente con incluir su dirección IP dentro del bloque donde se declara $loggable.

nginx
	map $remote_addr $loggable { 
         
	default 1;
	79.117.135.158 0;
	
	} 

/etc/nginx

En Gnu/Linux, el directorio /etc/nginx contiene los archivos de configuración de Nginx, como los virtual-hosts que están divididos en dos directorios. Siendo /etc/nginx/sites-available para los sitios disponibles y /etc/nginx/sites-enabled para los sitios habilitados publicamente.

Si un virtual-host existe en sites-available, mientras no exista un enlace simbólico que apunte a sites-enables, Nginx no lo considera un sitio público. Por lo tanto no será reconocido por herramientas como Certbot

También contiene archivos de configuración globales como nginx.conf o mime.types, pero no son los únicos. Existe también el directorio conf.d, que sirve para agrupar configuraciones.

sites-available

En una instalación limpia de Nginx, sites-available contiene un único archivo llamado default. Este archivo es un ejemplo sobre como se debe configurar un virtual-host en el directorio sites-available.

Cada administrador tiene su propia nomenclatura para nombrar a los virtual-hosts. Y dejando de lado por un momento mi fascinación por escribir en tercera persona, recomiendo encarecidamente que uséis el nombre del dominio o subdominio para nombrar al virtual-host cuya configuración gestiona.

Debajo os dejo un ejemplo con mi sitio web daniloarancibia.es, pero dentro de un contenedor Docker con la imagen de Debian Trixie

nginx
root@ryzen-7950x-128gb-mad-debian:/etc/nginx/sites-available# ls -la 
total 16
drwxr-xr-x 1 root root 4096 Jul  3 10:54 .
drwxr-xr-x 1 root root 4096 Jul  3 10:06 ..
-rw-r--r-- 1 root root    0 Jul  3 10:54 api.daniloarancibia.es
-rw-r--r-- 1 root root    0 Jul  3 10:54 daniloarancibia.es
-rw-r--r-- 1 root root 2412 Jun 27 20:25 default
-rw-r--r-- 1 root root    0 Jul  3 10:54 music.daniloarancibia.es
-rw-r--r-- 1 root root    0 Jul  3 10:54 sonarqube.daniloarancibia.es
-rw-r--r-- 1 root root    0 Jul  3 10:54 workspace.daniloarancibia.es

Incluso es recomendable organizarlos por directorios de la siguiente manera:

nginx
root@ryzen-7950x-128gb-mad-debian:/etc/nginx/sites-available# ls -la
total 20
drwxr-xr-x 1 root root 4096 Jul  3 11:00 .
drwxr-xr-x 1 root root 4096 Jul  3 10:06 ..
drwxr-xr-x 2 root root 4096 Jul  3 11:00 daniloarancibia.es
-rw-r--r-- 1 root root 2412 Jun 27 20:25 default
nginx
root@ryzen-7950x-128gb-mad-debian:/etc/nginx/sites-available# ls -la daniloarancibia.es/
total 8
drwxr-xr-x 2 root root 4096 Jul  3 11:00 .
drwxr-xr-x 1 root root 4096 Jul  3 11:00 ..
-rw-r--r-- 1 root root    0 Jul  3 10:54 api.daniloarancibia.es
-rw-r--r-- 1 root root    0 Jul  3 10:54 daniloarancibia.es
-rw-r--r-- 1 root root    0 Jul  3 10:54 music.daniloarancibia.es
-rw-r--r-- 1 root root    0 Jul  3 10:54 sonarqube.daniloarancibia.es
-rw-r--r-- 1 root root    0 Jul  3 10:54 workspace.daniloarancibia.es

A nivel funcional lo anterior no afecta en lo absoluto. Sin embargo, para mantener múltiples dominios es casi obligatorio llevar un orden dentro de sites-available, cosa que se agradece especialmente si no eres el único administrador del servidor.

default

El siguiente es un ejemplo de un archivo de configuración default en una instalación limpia de Nginx en Debian Trixie.

nginx
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
#
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
#
# This file will automatically load configuration files provided by other
# applications, such as Drupal or Wordpress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##

# Default server configuration
#
server {
	listen 80 default_server;
	listen [::]:80 default_server;

	# SSL configuration
	#
	# listen 443 ssl default_server;
	# listen [::]:443 ssl default_server;
	#
	# Note: You should disable gzip for SSL traffic.
	# See: https://bugs.debian.org/773332
	#
	# Read up on ssl_ciphers to ensure a secure configuration.
	# See: https://bugs.debian.org/765782
	#
	# Self signed certs generated by the ssl-cert package
	# Don't use them in a production server!
	#
	# include snippets/snakeoil.conf;

	root /var/www/html;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	server_name _;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}

	# pass PHP scripts to FastCGI server
	#
	#location ~ \.php$ {
	#	include snippets/fastcgi-php.conf;
	#
	#	# With php-fpm (or other unix sockets):
	#	fastcgi_pass unix:/run/php/php7.4-fpm.sock;
	#	# With php-cgi (or other tcp sockets):
	#	fastcgi_pass 127.0.0.1:9000;
	#}

	# deny access to .htaccess files, if Apache's document root
	# concurs with nginx's one
	#
	#location ~ /\.ht {
	#	deny all;
	#}
}


# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
#	listen 80;
#	listen [::]:80;
#
#	server_name example.com;
#
#	root /var/www/example.com;
#	index index.html;
#
#	location / {
#		try_files $uri $uri/ =404;
#	}
#}

El archivo default debe permanecer intacto, sin modificar, mover o eliminar. La razón es simple. Al actualizar el servidor con el archivo intacto y si entre los paquetes con actualizaciones disponibles está Nginx, el archivo se actualizará automáticamente con nueva información en caso que la haya.

La naturaleza de wiki y de fall back del archivo genera algunas contradicciones. La primera llega con el hecho que default no debe tener un enlace simbólico que apunte hacia sites-enabled, aunque por defecto y con fines ilustrativos, existe un enlace simbólico en sites-enabled desde el primer momento.

La razón está implícita, personalizarlo no es una opción. Además, un archivo susceptible a cambios y con una directiva tan importante como default_server genera dudas sobre como tratar con el, pero su naturaleza de plantilla es la respuesta a estas contradicciones. 

Para evitar divergencias se debe crear una copia con otro nombre, por ejemplo:

bash
/etc/nginx/sites-available# cp default main

Y eliminar el enlace simbólico de default de sites-enabled:

bash
/etc/nginx/sites-available# rm -rf /etc/nginx/sites-enabled/default

Y finalmente remplazarlo por la copia:

bash
ln -s /etc/nginx/sites-available/main /etc/nginx/sites-enabled/main

Ahora Main es solo un archivo que funciona como fall back y default como una wiki sobre los virtual-hosts. Lo anterior además ser un ejercicio de separación de responsabilidades, permite que Main se pueda personalizar sin las consecuencias de modificar default.

Main podría incluso no existir como remplazo de default como fall back en sites-enabled y Nginx mostraría el suyo propio, como el siguiente:

Fall back por defecto de Nginx

La directiva mencionada anteriormente, default_server, sirve para  indicar a Nginx que archivo resuelve las peticiones cuya cabecera no corresponde a ningún virtual-host del servidor.

¿Por qué un enlace simbólico y no una copia? Un enlace simbólico es, de forma simplificada, un puntero al inodo del archivo original mientras que una copia es un inodo nuevo.

Esto significa que cada cambio en el archivo original se verá reflejado en el enlace simbólico. La separación a nivel de directorios pero sincronización a través de los enlaces simbólicos permiten habilitar o no un virtual-host y mantener un orden coherente entre dominios. 

conf.d

conf.d es un directorio dedicado para almacenar de forma organizada configuraciones globales del servidor o de los virtual-hosts. A diferencia de sites-available y sites-enabled, en una instalación limpia conf.d no contiene ningún archivo de configuración por defecto.

El concepto es similar a lo que se explica en el bloque sites-available pero esta vez en el contexto de configuraciones globales o específicas de cada virtual-host.

bash
root@ryzen-7950x-128gb-mad-debian:/etc/nginx/conf.d# ls -l
total 0
-rw-r--r-- 1 root root 0 Jul  8 14:33 block-empty-user-agents.conf
-rw-r--r-- 1 root root 0 Jul  8 14:33 block-ips.conf
-rw-r--r-- 1 root root 0 Jul  8 14:33 block-routes-globally.conf
-rw-r--r-- 1 root root 0 Jul  8 14:33 white-list.conf

Un modo de representarlo de forma organizada es la siguiente:

bash
conf.d/http
conf.d/stream
conf.d/compression

nginx.conf

nginx.conf es el archivo principal de configuración de Nginx, está estrechamente relacionado con el directorio conf.d y los virtual-hosts.

El siguiente ejemplo supone que el archivo white-list.conf existe en el directorio conf.d y que su único propósito es permitir que un grupo o un rango de IPS puedan acceder a recursos privados de un virtual-host en específico.

Para ello sería suficiente con incluir el archivo white-list en el virtual-host con la directiva include de la siguiente forma:

bash
include /etc/nginx/conf.d/white-list.conf;

El ejemplo anterior es útil en diversas situaciones, una de ellas es cuando se está migrando de una web hecha con Prestashop a una web hecha a medida que además cuenta con un nuevo diseño. Lo ideal es que el resto de departamentos den su feedback sobre la nueva web o Q&A pueda ir a la par con el equipo de desarrollo. Para que lo anterior sea posible debe existir un subdominio, por ejemplo: staging.daniloarancibia.es

De esta forma además de recibir feedback interno, también se evita exponer páginas que no deberían ser publicas en una etapa tan temprana. Y si las IPS del archivo white-list.conf solo se pueden utilizar en la oficina, también se evitan filtraciones.

Ahora bien, si en lugar de incluir el archivo de configuración white-list.conf en un virtual-host, se incluye en nginx.conf, las configuraciones del archivo ya no solo afectan a un solo virtual-host, sino que se aplican a todos los virtual-hosts disponibles, sin excepción alguna.

mime.types

mime.types es un archivo de configuración que Nginx utiliza para informar al cliente como debe tratar los recursos que recibe desde el servidor.

bash
types { 
    text/html                                        html htm shtml; 
    text/css                                         css; 
    text/xml                                         xml; 
    image/gif                                        gif; 
    image/jpeg                                       jpeg jpg; 
    application/javascript                           js; 
    application/atom+xml                             atom; 
    application/rss+xml                              rss; 

    text/mathml                                      mml; 
    text/plain                                       txt; 
    text/vnd.sun.j2me.app-descriptor                 jad; 
    text/vnd.wap.wml                                 wml; 
    text/x-component                                 htc; 

    image/avif                                       avif; 
    image/png                                        png; 
    image/svg+xml                                    svg svgz; 
    image/tiff                                       tif tiff; 
    image/vnd.wap.wbmp                               wbmp; 
    image/webp                                       webp; 
    image/x-icon                                     ico; 
    image/x-jng                                      jng; 
    image/x-ms-bmp                                   bmp; 

    font/woff                                        woff; 
    font/woff2                                       woff2; 

    application/java-archive                         jar war ear; 
    application/json                                 json; 
    application/mac-binhex40                         hqx; 
    application/msword                               doc; 
    application/pdf                                  pdf; 
    application/postscript                           ps eps ai; 
    application/rtf                                  rtf; 
    application/vnd.apple.mpegurl                    m3u8; 
    application/vnd.google-earth.kml+xml             kml; 
    application/vnd.google-earth.kmz                 kmz; 
    application/vnd.ms-excel                         xls; 
    application/vnd.ms-fontobject                    eot; 
    application/vnd.ms-powerpoint                    ppt; 
    application/vnd.oasis.opendocument.graphics      odg; 
    application/vnd.oasis.opendocument.presentation  odp; 
    application/vnd.oasis.opendocument.spreadsheet   ods; 
    application/vnd.oasis.opendocument.text          odt; 
    application/vnd.openxmlformats-officedocument.presentationml.presentation 
                                                     pptx; 
    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 
                                                     xlsx; 
    application/vnd.openxmlformats-officedocument.wordprocessingml.document 
                                                     docx; 
    application/vnd.wap.wmlc                         wmlc; 
    application/wasm                                 wasm; 
    application/x-7z-compressed                      7z; 
    application/x-cocoa                              cco; 
    application/x-java-archive-diff                  jardiff; 
    application/x-java-jnlp-file                     jnlp; 
    application/x-makeself                           run; 
    application/x-perl                               pl pm; 
    application/x-pilot                              prc pdb; 
    application/x-rar-compressed                     rar; 
    application/x-redhat-package-manager             rpm; 
    application/x-sea                                sea; 
    application/x-shockwave-flash                    swf; 
    application/x-stuffit                            sit; 
    application/x-tcl                                tcl tk; 
    application/x-x509-ca-cert                       der pem crt; 
    application/x-xpinstall                          xpi; 
    application/xhtml+xml                            xhtml; 
    application/xslt+xml                             xsl xslt; 
    application/xspf+xml                             xspf; 
    application/zip                                  zip; 

    application/octet-stream                         bin exe dll; 
    application/octet-stream                         deb; 
    application/octet-stream                         dmg; 
    application/octet-stream                         iso img; 
    application/octet-stream                         msi msp msm; 

    audio/midi                                       mid midi kar; 
    audio/mpeg                                       mp3; 
    audio/ogg                                        ogg; 
    audio/x-m4a                                      m4a; 
    audio/x-realaudio                                ra; 

    video/3gpp                                       3gpp 3gp; 
    video/mp2t                                       ts; 
    video/mp4                                        mp4; 
    video/mpeg                                       mpeg mpg; 
    video/ogg                                        ogv; 
    video/quicktime                                  mov; 
    video/webm                                       webm; 
    video/x-flv                                      flv; 
    video/x-m4v                                      m4v; 
    video/x-matroska                                 mkv; 
    video/x-mng                                      mng; 
    video/x-ms-asf                                   asx asf; 
    video/x-ms-wmv                                   wmv; 
    video/x-msvideo                                  avi; 
} 

Si la aplicación se sirve a través de un proxy, es probable que esta ya envíe sus propios headers con el tipo de contenido para cada recurso.

En frameworks como NextJS esto no supone un problema funcional. Porque si el mime type no existe en mime.types, el framework ya está enviando los headers por su cuenta. Esta división de dependencias provoca que al intentar forzar un cambio de headers en NextJS a través de  Nginx se duplique el header.

Si la aplicación se sirve como recurso estático a través de Nginx y los recursos están en /var/www/html/, el fall back funcional será que el navegador intentará descargar el recurso en lugar de interpretarlo. 

C'est tout.