Apache vs. NGINX
La primera versión del servidor HTTP Apache nace en 1995. Sin embargo, a día de hoy, más de 20 años después. El servidor web ruso nginx, que se pronuncia como “Engine-x”, también de código abierto, es el que posee una cuota de mercado mayor, creciendo de manera exponencial. Algo que resulta especialmente doloroso para la Apache Foundation es que la mayoría de páginas web con una buena posición en el ranking de Alexa se entregan por medio de nginx, tal y como muestra un estudio estadístico de W3Techs que se actualiza regularmente. No solo los grandes buscadores rusos como Rambler y Yandex, el servicio de correo electrónico Mail.RU o la red social VK utilizan el ligero servidor, sino que también proveedores internacionales como Dropbox, Netflix, WordPress y FastMail utilizan nginx para mejorar el rendimiento de sus servicios. ¿Significa esto que el Apache HTTP Server forma parte del pasado?
El servidor HTTP Apache, conocido en la comunidad internauta por su versión economizada “Apache”, es un proyecto de software impulsado bajo el patrocinio de la Apache Foundation. Esta convención también se aplica a esta guía y al hablar de Apache se hace referencia al software y no al fabricante.
Los desafíos de la Web 2.0
Owen Garrett, responsable de productos de Nginx, Inc., describe al servidor web Apache en el blog de nginx.com en 2015 como el “backbone” (columna vertebral) de la Web 1.0 y pone de relieve su importancia para el desarrollo de Internet alrededor del cambio de milenio. El notable éxito del servidor web reside en la sencilla arquitectura del software, si bien se basa en decisiones de diseño orientadas a una World Wide Web que no se puede comparar con la actual. Hace 20 años las páginas web tenían una estructura más simple, el ancho de banda era limitado y caro y, por el contrario, el tiempo de la CPU era en comparación más económico.
Hoy en día estamos ante una World Wide Web de segunda generación que muestra una cara muy diferente: tanto el número de usuarios como el tráfico web mundial se han multiplicado y lo mismo se puede decir del tamaño medio de las páginas así como de la cantidad de componentes que los navegadores deben consultar y renderizar para poderlas representar. Una parte cada vez mayor de la comunidad en Internet ha crecido acostumbrada a las posibilidades de la Web 2.0 y este grupo de usuarios no está habituado a esperar varios segundos y mucho menos minutos para descargar una página web.
Estos cambios han supuesto en los últimos años un desafío cada vez mayor para el servidor HTTP Apache. Owen Garret señala como responsable a la arquitectura basada en procesos propia de Apache, que no se puede escalar adecuadamente a la vista de un tráfico cada vez más elevado. Esta debilidad fue una de las principales motivaciones para desarrollar nginx en el año 2002, que fue por unos derroteros diferentes debido a su arquitectura dirigida por eventos. nginx fue creado por el desarrollador de software ruso Igor Sysoev, se utiliza tanto como servidor web como proxy inverso o proxy de correo electrónico y está diseñado atendiendo a las necesidades del buscador ruso Rambler.
A continuación te hablamos de la relación entre Apache y nginx y te informamos sobre las diferencias arquitectónicas, la configuración o las posibilidades de desarrollo, pero también sobre la compatibilidad, la documentación y la asistencia técnica.
Diferencias arquitectónicas
Los servidores web Apache y nginx presentan diferencias en cuanto a la arquitectura del software en relación con la gestión de la conexión, la interpretación de las solicitudes de los clientes, el manejo de los contenidos web estáticos y dinámicos y la configuración.
Gestión de la conexión
En la comparación de nginx vs. Apache surgen diferencias básicas en la manera como manejan las solicitudes entrantes de los clientes (requests). Mientras que Apache parte de una arquitectura basada en procesos, la gestión de la conexión en nginx se erige sobre la base de un algoritmo de procesamiento dirigido por eventos, lo que permite procesar solicitudes ahorrando recursos incluso cuando entran en juego varias conexiones simultáneamente. Esto constituye, según los desarrolladores de nginx, una gran ventaja frente al servidor HTTP Apache, que desde la versión 2.4 ofrece la posibilidad de implementar eventos. Veamos a continuación las diferencias en detalle.
El servidor web Apache adopta un enfoque en el que las solicitudes de los clientes se tramitan en un proceso o thread (hilo) separado. El single threading o proceso con un único hilo, el modo operativo original del Apache HTTP server, plantea problemas tarde o temprano con el bloqueo de I/O: los procesos que requieren operaciones de escritura o lectura se procesan estrictamente uno tras otro. Así, la solicitud posterior permanecerá en espera hasta que se haya respondido a la anterior. Esto se puede evitar iniciando varios procesos de single threading simultáneamente, una estrategia que conlleva un consumo elevado de recursos.
Como alternativa pueden usarse mecanismos de multithreading o de multihilos. A diferencia del single threading, en el que en todo proceso hay disponible un thread para responder a las solicitudes de los clientes, el multithreading ofrece la posibilidad de ejecutar varios hilos en un mismo proceso. Como los hilos de Linux necesitan menos recursos que procesos, el multithreading permite compensar las amplias necesidades de recursos de la arquitectura basada en procesos del servidor HTTP Apache.
Para integrar mecanismos que permitan el procesamiento paralelo de peticiones en Apache puede recurrirse a uno de estos tres módulos de multiprocesamiento (MPM): mpm_prefork, mpm_worker, mpm_event.
- mpm_prefork: el módulo de Apache “prefork” garantiza la gestión multiproceso basándose en un mecanismo de single threading. El módulo crea un proceso padre que ofrece múltiples procesos hijo y en cada uno de ellos funciona un thread o hilo que permite responder a la solicitud del cliente. Siempre que haya más procesos single thread disponibles que peticiones entrantes de clientes, las requests se procesarán de manera inmediata.
El número de procesos de single threading disponibles se define con ayuda de las opciones de configuración del servidor “MinSpareServers” y “MaxSpareServers”. El módulo prefork alberga, sin embargo, los inconvenientes de rendimiento del single threading anteriormente mencionados, si bien la independencia de los procesos resulta ventajosa: si se pierde la conexión debido a un proceso defectuoso, por lo general esto no se refleja en las conexiones editadas en otros procesos.
- mpm_worker: con el módulo “worker”, Apache ofrece a los usuarios un mecanismo de multithreading para el procesamiento paralelo de las solicitudes de los clientes. El número de threads que debe iniciarse por proceso puede determinarse con la opción de configuración del servidor “ThreadsPerChild”. El módulo prevé un thread por conexión TCP. Siempre que haya más procesos disponibles que solicitudes entrantes, las requests se procesan en paralelo. El proceso padre (httpd) vigila los threads desocupados.
Los usuarios pueden recurrir a los comandos “MinSpareThreads” y “MaxSpareThreads” para definir a partir de qué cantidad de hilos desocupados deben generarse nuevos threads o eliminarse de la memoria ciertos hilos en ejecución. El módulo worker no necesita tantos recursos como el prefork. Puesto que las conexiones no se procesan en procesos separados, un thread defectuoso pude repercutir en el procedimiento completo de multithreading y en todas las conexiones que se elaboran en él. Además, tanto worker como prefork son propensos a las sobrecargas a través de las llamadas conexiones Keep Alive (véase más abajo).
- mpm_event: desde la versión 2.4, el servidor HTTP Apache ofrece el tercer módulo de multiprocessing llamado event, que está destinado a un entorno productivo. Este es una variante del módulo worker y se ocupa de la distribución de carga entre los hilos iniciados. A ello se añade un listener thread por proceso de multithreading, que se encarga de las solicitudes de los clientes y asigna para ello tareas relacionadas en hilos del módulo worker. El módulo event fue desarrollado para optimizar la relación con las conexiones Keep Alive, es decir, conexiones TCP que no deben contener ningún tipo de fallos para posibilitar la transmisión de otras solicitudes de los clientes o de las respuestas de los servidores (responses). Si se recurre al clásico módulo worker, sus hilos mantienen las conexiones establecidas y, por lo tanto, se bloquean incluso si no se recibe ninguna otra solicitud, lo que, en caso de una gran cantidad de conexiones Keep Alive puede dar lugar a la sobrecarga del servidor. Por el contrario, el módulo event externaliza el mantenimiento de conexiones Keep Alive en el listener thread independiente. Así, los hilos de worker no se bloquean y están disponibles para procesar otras solicitudes.
El siguiente gráfico muestra una presentación esquemática de la arquitectura basada en procesos del servidor web Apache utilizando el módulo worker:
Dependiendo del módulo utilizado, Apache soluciona el problema de la concurrencia (que también hace referencia a la respuesta simultánea a varias solicitudes de clientes) ya sea mediante procesos adicionales o mediante threads. Ambas estrategias van acompañadas de unos costes adicionales, lo que se convierte en un factor limitante a la hora de escalar un servidor Apache.
La enorme necesidad de recursos del principio “un proceso por conexión” se debe al hecho de que para cada proceso adicional se tiene que facilitar un entorno de tiempo de ejecución propio, el cual requiere la asignación del tiempo de la CPU y de una memoria separada. Además, todo módulo de Apache que tenga que estar disponible en un proceso worker debe cargarse por separado. Por el contrario, los hilos comparten un entorno de ejecución (el programa) y un espacio para direcciones en la memoria. La sobrecarga de los hilos adicionales es, por lo tanto, inferior a la de los procesos. Sin embargo, el multithreading requiere muchos recursos en lo que a cambios de contexto (context switches) se refiere.
Estos cambios de contexto hacen referencia al procedimiento por el que el sistema de un proceso o hilo se cambia por otro, para lo que tiene que protegerse el contexto del proceso o hilo finalizado y generarse o restablecerse el nuevo, convirtiéndose así en un procedimiento administrativo que requiere mucho tiempo y en el que tanto el registro de la CPU como las diversas tablas y listas han de cargarse y protegerse.
El módulo mpm_event contiene un mecanismo event para el servidor HTTP Apache que externaliza la edición de las conexiones entrantes en un hilo listener. Este permite finalizar conexiones que ya no son necesarias (también las conexiones Keep Alive) y, así, reducir el consumo de recursos. Sin embargo, el problema de los cambios de contexto que requieren muchos recursos no se soluciona si el hilo listener traslada las requests de las conexiones mantenidas a hilos worker separados.
Por el contrario, la arquitectura basada en eventos de nginx realiza la concurrencia sin que sea necesario un proceso o hilo adicional para cada conexión nueva, y es que un único procedimiento nginx es capaz de procesar miles de conexiones HTTP simultáneamente. Esto se lleva a cabo mediante un mecanismo de bucles conocido como event loop o bucle de eventos, que permite procesar las solicitudes de los clientes de manera asincrónica en un hilo.
En teoría, nginx recurre al procesamiento de conexiones con un solo proceso de single threading. Por lo general, para poder sacar todo el provecho al hardware, el servidor web se inicia con un proceso worker por núcleo de procesador (CPU) de la máquina subyacente.
A diferencia del servidor web Apache, en el que se puede limitar el número de procesos o hilos activos con valores mínimos o máximos, nginx ofrece un modelo de procesos predecible que se ajusta con exactitud al hardware subyacente. Dicho modelo comprende un proceso maestro, los procesadores de ayuda cache loader y cache manager, así como un número de procesadores worker adaptados a los diferentes núcleos de procesadores y definidos claramente por medio de la configuración.
- Proceso maestro: el proceso maestro es un proceso padre que ejecuta las operaciones básicas como, por ejemplo, la lectura de la configuración del servidor, la unión de puertos y la creación de todos los tipos de procesos siguientes.
- Procesos colaboradores: nginx utiliza dos procesos para gestionar el caché, es decir, el cache loader y el cache manager.
- Cache loader: el cache loader es responsable de que el caché basado en el disco duro se cargue en la memoria.
- Cache manager: la tarea del cache manager es controlar que los registros del caché del disco duro muestren las dimensiones previamente configuradas y las restrinjan según las necesidades. Este proceso se activa periódicamente.
- Proceso worker: los procesos worker son responsables del procesamiento de conexiones, del acceso de escritura y lectura en el disco duro y de la comunicación con servidores upstream (servidores que proporcionan servicios a otros servidores). En otras palabras, son los únicos procesos del modelo de procesos de nginx que están continuamente activos.
El siguiente gráfico muestra una representación esquemática del modelo de procesos de nginx:
Todos los procesos worker que inicia el proceso maestro de nginx en el marco de la configuración comparten un set de listener sockets (puntos finales de comunicación). En lugar de iniciar un proceso o hilo propio para cada conexión entrante, en cada proceso worker se ejecuta un event loop que posibilita el procesamiento asincrónico de varios miles de conexiones en un mismo hilo sin bloquear el proceso. Para ello, los procesos worker escuchan en los listener sockets atentamente a los eventos producidos a través de conexiones entrantes, los aceptan y ejecutan procesos de lectura y escritura en el socket durante el procesamiento de peticiones HTTP.
En este contexto, nginx no provee de ningún mecanismo propio para la distribución de conexiones en procesos worker. En lugar de ello se utilizan las funciones centrales del sistema operativo. Los esquemas sobre cómo procesar las solicitudes entrantes se preparan a través de máquinas de estados (state machines) separadas para HTTP, raw TCP, SMTP, IMAP y POP3.
En términos más generales, nginx puede ser denominado como administrador de eventos, ya que recibe datos sobre eventos del kernel y comunica al sistema operativo cómo tiene que gestionar las tareas relacionadas. El procesamiento asincrónico de tareas en el event loop se basa en notificaciones de eventos, devoluciones de llamada (callbacks) y temporizadores. Estos mecanismos permiten que un proceso worker delegue una operación tras otra en el sistema operativo sin tener que esperar con pasividad al resultado de la operación o a la respuesta de los programas cliente. Por lo tanto, nginx funciona como orquestador para el sistema operativo, que se encarga de leer y escribir bytes.
Este tipo de gestión de la conexión solo genera una ligera sobrecarga para las conexiones adicionales. Todo lo que se necesita es un File Descriptor (FD) adicional y una mínima memoria adicional en el proceso worker. Por el contrario, los cambios de contexto que requieren una renderización intensiva se presentan cuando en un event loop no aparecen otros eventos. La efectividad a la hora de tramitar las solicitudes mediante un número elevado de conexiones predestina a nginx como distribuidor de carga para páginas web muy frecuentadas, como por ejemplo WordPress.com.
Con una arquitectura que soporta eventos, nginx ofrece una alternativa a la gestión de conexiones del servidor HTTP Apache basada en procesos, pero esta característica no es suficiente por sí misma para explicar por qué nginx saca tan buena nota en los tests Benchmark, pues desde la versión 2.4, Apache también soporta un mecanismo de procesamiento de las solicitudes de los clientes basado en eventos. En comparativas de servidores web del tipo Apache vs. nginx se debe prestar siempre atención, por ello, a los módulos utilizados por los servidores web para realizar los tests, a la configuración de los servidores y a las tareas que deben afrontarse.
Gestión de los contenidos web estáticos y dinámicos
En lo que respecta al manejo de los contenidos web dinámicos, nginx sigue una estrategia totalmente diferente a la del servidor HTTP Apache.
En principio, para poder entregar contenidos web dinámicos, un servidor web debe recurrir a un intérprete que tenga la capacidad de procesar el lenguaje de programación necesario, como PHP, Perl, Python o Ruby. Para ello, Apache contiene diversos módulos como mod_php, mod_perl, mod_python o mod_ruby, que permiten cargar el intérprete correspondiente directamente en el servidor web, de forma que posee de entrada la habilidad de procesar contenidos web dinámicos. Las funciones para la provisión de contenidos estáticos se implementan por medio de los módulos MPM anteriormente mencionados.
Por el contrario, nginx solo ofrece mecanismos para proporcionar contenidos web estáticos y la entrega de contenidos dinámicos se externaliza en servidores de aplicaciones especializados. En este caso, nginx hace de proxy entre el programa cliente y el servidor upstream. La comunicación tiene lugar a través de protocolos como HTTP, FastCGI, SCGI, uWSGI y Memcached. WebSphere, JBoss o Tomcat se erigen como posibles servidores de aplicaciones para la entrega de contenidos dinámicos, aunque también puede utilizarse el servidor HTTP Apache.
Ambas estrategias presentan ventajas e inconvenientes. Un módulo como mod_php permite al servidor web ejecutar código PHP y no se necesita para ello un servidor de aplicaciones adicional, lo que hace más cómoda la administración de páginas web dinámicas. Los módulos intérprete para los lenguajes de programación dinámicos tienen que cargarse por separado en cada proceso worker, al que se le encomienda la entrega del contenido. Si se da un gran número de procesos worker, esto conlleva una clara sobrecarga que nginx puede reducir, ya que solo se recurre al intérprete externalizado en caso necesario.
Mientras que nginx está orientado a la interacción con un intérprete externalizado, los usuarios de Apache pueden recurrir a ambas estrategias. Apache también puede emplearse para un servidor de aplicaciones que se encargue de la interpretación de contenidos web dinámicos. Por lo general, se utiliza el protocolo FastCGI, y la interfaz correspondiente se carga con el módulo mod_proxy_fcgi.
En la comparación Apache vs. nginx ambos servidores web permiten entregar páginas web dinámicas. Mientras que Apache interpreta por sí mismo y ejecuta el código de programa utilizado con ayuda de módulos, nginx confía esta tarea a un servidor de aplicaciones externo.
Interpretación de las solicitudes de los clientes
Para responder satisfactoriamente a las peticiones de los programas cliente, los servidores deben determinar cuáles son los recursos solicitados y donde se encuentran basándose en la propia request.
El servidor HTTP Apache fue concebido como servidor web. Por el contrario, nginx ofrece tanto funciones de servidor web como de servidor proxy, diferencia que se vuelve a manifestar sobre todo en la manera en que el software correspondiente interpreta las solicitudes de los clientes y clasifica los recursos en el servidor.
El servidor HTTP Apache se puede utilizar como servidor proxy con ayuda del módulo mod_proxy.
Tanto el servidor HTTP Apache como nginx cuentan con mecanismos que permiten interpretar requests entrantes como recursos físicos en el sistema de archivos o como URI (Uniform Resource Identifier). Mientras Apache trabaja normalmente en base a archivos, en nginx se da prioridad a los URI.
Si llega una solicitud de cliente al servidor HTTP Apache, este presupone, por lo general, que se debe consultar un recurso específico del sistema de archivos del servidor. Debido a que con los VirtualHosts Apache ofrece la posibilidad de proporcionar diferentes contenidos web en un mismo servidor bajo diversos nombres de host, direcciones IP o números de puerto, se debe indicar a qué VirtualHost hace referencia la solicitud. Para ello, el servidor web coteja el nombre del host, la dirección IP y el número del puerto al principio del URI de la petición con los VirtualHosts definidos en el fichero de configuración principal httpd.conf.
El siguiente ejemplo de código muestra una configuración de Apache en la que los dos dominios www.example.com y www.other-example.com se operan bajo la misma dirección IP:
NameVirtualHost *:80
<VirtualHost *:80>
ServerName www.example.com
ServerAlias example.com *.example.com
DocumentRoot /data/www/example
</VirtualHost>
<VirtualHost *:80>
ServerName www.other-example.com
DocumentRoot /data/www/other-example
</VirtualHost>
El asterisco (*) sirve como espaciador para cualquier dirección IP. Mediante la comparación del nombre de host incluido en la solicitud con la directiva ServerName Apache decide en qué DocumentRoot (directorio de inicio de un proyecto web) se debe buscar el recurso solicitado.
Si Apache ha encontrado el servidor deseado, el URI de la solicitud se proyecta por defecto en el sistema de archivos del servidor (mapping). Para ello, Apache emplea la ruta de acceso incluida en el URI y, en combinación con el DocumentRoot, se genera la ruta del recurso.
En una solicitud con el URI "http://www.example.org:80/public_html/images/logo.gif", Apache buscaría (partiendo del ejemplo anterior) el recurso adecuado siguiendo la ruta de archivo que aparece a continuación :
/data/www/example/public_html/images/logo.gif
Debido a que 80 es el puerto estándar para HTTP, en la práctica normalmente se prescinde de este dato.
Apache compara el URI de la solicitud con los bloques file y directory opcionales en la configuración. Estos permiten definir instrucciones especiales para las requests a las que se hace referencia en los archivos o directorios (incluidos los subdirectorios) seleccionados.
En el siguiente ejemplo se definen instrucciones especiales para el directorio public_html/images y el fichero private.html:
<VirtualHost *:80>
ServerName www.example.com
ServerAlias example.com *.example.com
DocumentRoot /data/www/example
<Directory var/www/example.com/public_html/images>
Order Allow,Deny
Allow from all
</Directory>
<Files public.html>
Order Allow,Deny
Deny from all
</Files>
</VirtualHost>
Además de este procedimiento habitual en la interpretación de las solicitudes de los clientes, con la directiva Alias Apache ofrece la posibilidad de indicar un directorio alternativo que tiene que analizar el recurso solicitado en lugar del DocumentRoot. Asimismo, el módulo mod_rewrite del servidor HTTP Apache permite a los usuarios describir o reenviar URL.
Puedes obtener más información sobre el módulo mod_rewrite en nuestro artículo sobre cómo reescribir URL con mod_rewrite.
Cuando Apache tiene que consultar recursos depositados fuera del sistema de archivos del servidor, se utiliza la directiva Location (ubicación), que permite definir instrucciones para determinados URI.
Lo que puede ser una excepción en Apache, se convierte en algo estándar en nginx, que analiza el URI de la solicitud y lo compara con los bloques server y location en la configuración del servidor web. Solo después puede tener lugar (si es necesario) el mapeo en el sistema de archivos y la combinación con el root (DocumentRoot del servidor Apache).
Con ayuda de la directiva Server (servidor), nginx averigua qué host es el responsable de responder a la solicitud del cliente. El bloque server corresponde a un VirtualHost en la configuración de Apache. Para ello se deben sincronizar el nombre del host, la dirección IP y el número del puerto del URI de la solicitud con todos los bloques server en la configuración del servidor web. El siguiente ejemplo de código muestra tres bloques server en el fichero de configuración de nginx nginx.conf:
server {
listen 80;
server_name example.org www.example.org;
...
}
server {
listen 80;
server_name example.net www.example.net;
...
}
server {
listen 80;
server_name example.com www.example.com;
...
}
Todos los bloques de servidor suelen contener una serie de bloques de ubicación. En el ejemplo actual estos se sustituyen por un espaciador (...).
La comparación entre el URI de la solicitud y los bloques location en un bloque server se realiza solo cuando se encuentra el servidor solicitado. Para ello, nginx lee los bloques de ubicación especificados y busca la ubicación más acorde con el URI de la solicitud. Los bloques location contienen instrucciones específicas que indican a nginx cómo se tiene que tramitar la solicitud correspondiente.
Aquí se pueden definir las ubicaciones de manera que se interpreten como prefijo para una ruta, como coincidencia exacta o como expresión regular (Regular Expression, RegEx). En la sintaxis de la configuración del servidor se utilizan, entre otros, los siguientes modificadores:
Sin modificador | La directiva Location se interpreta como prefijo. Todas las requests cuyo URI muestra el prefijo definido en la directiva Location son consideradas conforme a dicha location. Si no se encuentra una location específica, la solicitud se procesa según los datos del bloque ubicación. |
= | La directiva Location se interpreta como correspondencia exacta. Todas las requests con correspondencia exacta cuyo URI coincida exactamente con la secuencia de caracteres de la directiva Location se procesan según los datos en el bloque ubicación. |
~ | La directiva Location se interpreta como expresión regular. Todas las requests cuyo URI coincide con la expresión regular se procesan según los datos del bloque ubicación. Las mayúsculas y las minúsculas se evalúan en la comparación (case sensitive). |
~* | La directiva Location se interpreta como expresión regular. Todas las requests cuyo URI coincide con la expresión regular se procesan según los datos del bloque ubicación. Las mayúsculas y las minúsculas no se evalúan en la comparación (case insensitive). |
El siguiente ejemplo muestra tres bloques de ubicación que indican cómo se tienen que editar las solicitudes entrantes para los dominios example.org y www.example.org:
server {
listen 80;
server_name example.org www.example.org;
root /data/www;
location / {
index index.html index.php;
}
location ~* \.(gif|jpg|png)$ {
expires 30d;
}
location ~ \.php$ {
fastcgi_pass localhost:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
Basándose en una solicitud de cliente con el URI "http://www.example.org:80/logo.gif", nginx procede de la siguiente manera para interpretar las siguientes peticiones y entregar los recursos deseados:
http://www.example.org:80/logo.gif
http://www.example.org:80/index.php
Primero, nginx determina la ubicación específica del prefijo, para lo que el servidor web lee todas las Locations (ubicaciones) sin modificador de la lista y se para en la primera que coincida con la solicitud. A continuación se leen todas las Locations marcadas con el modificador RegEx (~) y también se utiliza la primera opción. Si el servidor web no encuentra ninguna ubicación RegEx apropiada, este recurrirá a la primera ubicación de prefijo como último recurso.
La solicitud "www.example.org:80/logo.gif" coincide tanto con la ubicación del prefijo / como con la expresión regular \.(gif|jpg|png)$. En este caso nginx reproduciría la solicitud en combinación con el root en la ruta de archivo /data/www/logo.gif y entregaría el recurso correspondiente al cliente. El encabezado expires indica cuándo se queda obsoleta una respuesta: en el ejemplo actual tras 30 días, es decir, expires 30d.
La solicitud de la página PHP con el URI "www.example.org:80/index.php" coincide tanto con la prefix location / como con la RegEx location ~ \.php$, a la que se da un tratamiento preferente. nginx entrega la solicitud a un servidor FastCGI, que escucha a un localhost:9000 y es responsable de la tramitación de contenidos web dinámicos. Así, la directiva fastcgi_param coloca el parámetro FastCGI SCRIPT_FILENAME en /data/www/index.php. A continuación se ejecuta el archivo en el servidor upstream. La variable $document_root corresponde a la directiva root, la variable $fastcgi_script_name a la parte del URI que le sigue al nombre del host y al número de puerto, es decir, /index.php.
Este procedimiento de interpretación de solicitudes de clientes, que a simple vista puede ser algo complicado, guarda relación con los diferentes campos de aplicación en los que se utiliza nginx. En comparación con el procedimiento principal basado en archivos del Apache HTTP Server, la interpretación de requests basada en URI posibilita una mayor flexibilidad en cuanto al tratamiento de los diferentes modelos de solicitud. Esto es necesario, por ejemplo, cuando nginx no funciona como servidor web, sino como servidor proxy o de correo electrónico.
Apache se utiliza principalmente como servidor web e interpreta las solicitudes de los clientes basándose sobre todo en archivos. Por el contrario, nginx trabaja normalmente con URI y así es capaz de ajustarse a otros patrones de solicitudes.
Configuración
Frente al servidor HTTP Apache, a nginx se le atribuye una mayor velocidad al entregar contenidos web estáticos, lo que se debe, entre otros factores, a diferencias en la configuración. Además del fichero de configuración principal httpd.conf, el servidor web Apache ofrece a los administradores la posibilidad de gestionar los niveles de directorios, donde entran en juego los llamados ficheros .htaccess. En principio, estos archivos de configuración descentralizados pueden implementarse en cualquier directorio del servidor. Las instrucciones definidas en .htaccess hacen referencia al directorio que contiene el archivo de configuración así como a sus subdirectorios. En la práctica se utilizan los ficheros .htaccess para limitar el acceso a los directorios a unos usuarios determinados, para crear una protección por contraseña o para definir reglas para la navegación por los directorios, para los mensajes de error, las redirecciones o los contenidos alternativos. Es importante señalar que todo ello puede configurarse de un modo central en el fichero httpd.conf. Sin embargo, .htaccess es relevante en modelos de alojamiento web como el shared hosting o alojamiento compartido, en el que el acceso al archivo de configuración central queda reservado al proveedor del hosting. La configuración descentralizada vía .htaccess permite autorizar a los usuarios a administrar unas áreas determinadas del sistema de archivos del servidor como, por ejemplo, para directorios de proyectos seleccionados, sin otorgarles acceso a la configuración principal. Además, los cambios surten efecto inmediatamente y sin necesidad de reiniciar. Por el contrario, ngingx ofrece opciones fundamentales de configuración y todas las instrucciones se definen en el fichero nginx.conf. Accediendo a él, el usuario puede controlar todo el servidor. A diferencia de Apache, el acceso administrativo no puede restringirse a los directorios seleccionados, lo que tiene ventajas e inconvenientes. La configuración central de ngingx es menos flexible que el concepto del servidor HTTP Apache y ofrece una clara ventaja de seguridad: solo los usuarios con permisos de superusuario pueden realizar cambios en la configuración del servidor web. Sin embargo, la desventaja del rendimiento de la configuración descentralizada vía .htaccess es más importante que el argumento de la seguridad. En la documentación del servidor HTTP Apache los desarrolladores recomiendan evitar el uso de .htaccess siempre que sea posible acceder a httpd.conf debido principalmente al procedimiento por el que Apache lee e interpreta los archivos de configuración. Como ya se ha indicado anteriormente, Apache sigue un esquema basado en archivos para responder a las solicitudes de los clientes. Debido a que la arquitectura de Apache permite una configuración descentralizada, en el camino hacia el recurso solicitado, el servidor web busca el fichero .htaccess en todos los directorios a lo largo de la ruta del archivo y lee e interpreta todos los archivos de configuración que recorre, un esquema que ralentiza el servidor web considerablemente.
En principio, los administradores de Apache pueden elegir si quieren recurrir a las posibilidades de configuración descentralizadas del servidor web y aceptar las ventajas e inconvenientes que implican. En la documentación, los desarrolladores ponen de relieve que todos los ajustes de .htaccess pueden realizarse mediante bloques de directorio en el fichero de configuración principal httpd.conf.
Para desactivar o restringir la configuración descentralizada en Apache se debe recurrir a la directiva AllowOverride en los bloques de directorio del fichero de configuración principal httpd.conf e indicar None. Esto señala al servidor web que ignore todos los ficheros .htaccess en directorios debidamente configurados.
<VirtualHost *:80>
ServerName example.com;
...
DocumentRoot /data/www/example
<Directory /data/www/example>
AllowOverride None
...
</Directory>
...
</VirtualHost>
La configuración del ejemplo ordena al servidor que ignore todos los ficheros .htaccess para el host example.com.
A diferencia de nginx, que está configurado de forma centralizada, Apache ofrece con .htaccess una configuración descentralizada y basada en directorios. Si se utilizan ficheros .htaccess, el servidor web pierde velocidad
Posibilidades de extensión
Los dos servidores web de nuestra comparativa se basan en un sistema modular en el que el software principal puede ampliarse con componentes adicionales en caso necesario. Hasta la versión 1.9.10, nginx siguió una estrategia de manejo de módulos diferente a la de su competidor. El Apache HTTP Server ofrece dos posibilidades para ampliar el software central: los módulos pueden o bien compilarse durante el desarrollo en los archivos binarios de Apache o cargarse de forma dinámica durante el tiempo de ejecución. Se pueden distinguir tres categorías de módulos de Apache:
- Módulo básico: los módulos básicos de Apache comprenden todos los componentes que proveen las funciones principales del servidor web.
- Módulos de extensión: las extensiones son módulos de la Apache Foundation que se proporcionan como componente especial de la Apache Distribution. La documentación sobre Apache ofrece una visión general sobre todos los módulos incluidos en la configuración estándar de la versión 2.4 de Apache.
- Módulos de proveedores externos: la Apache Foundation no ofrece estos módulos, sino proveedores externos o programadores autónomos.
En nginx, sin embargo, la modularidad se restringe a componentes de extensión estáticos que se tienen que compilar en el archivo binario del software principal. Para los usuarios que no estaban acostumbrados a gestionar sus propios componentes de software sin el gestor de paquetes de la distribución correspondiente, este tipo de extensión de software limitó considerablemente la flexibilidad del servidor web. A este respecto, el equipo de desarrolladores ha introducido algunas mejoras: desde la versión 1.9.11 (Release 09.02.2016), nginx soporta mecanismos que permiten convertir módulos estáticos en dinámicos para que estos puedan cargarse durante el tiempo de ejecución a través de archivos de configuración. En ambos casos se emplea la API del módulo del servidor. En relación con esto hay que tener en cuenta que no todos los módulos de nginx pueden convertirse en módulos dinámicos. Los módulos que parchean el código fuente del software de servidor no deben cargarse como módulos dinámicos. Además, en los ajustes básicos nginx limita a 128 el número de módulos dinámicos que pueden cargarse simultáneamente. Para aumentarlo, otorga el valor deseado a la constante en NGX_MAX_DYNAMIC_MODULES en el código fuente de nginx. Asimismo, para los módulos oficiales de la documentación de nginx los usuarios pueden recurrir a módulos de proveedores externos.
Ambos servidores web pueden implementarse con módulos. Además de los estáticos, también existen módulos dinámicos que, en caso necesario, pueden cargarse en el programa en curso.
Documentación y asistencia
Ambos proyectos de software están bien documentados y ofrecen a los usuarios información de primera mano a través de wikis y blogs.
Mientras que la documentación de nginx solo está disponible en inglés y en ruso, el proyecto Apache se distingue por su material informativo en numerosos idiomas, aunque está desactualizado, por lo que es imprescindible recurrir a la versión en inglés. La comunidad de cada proyecto open source es el medio de ayuda en caso de problemas y las listas de correo hacen las veces de foros de debate.
- Apache HTTP server: Mailing lists
- NGINX: Mailing lists
La transparencia sobre las posibles fechas de lanzamiento y las hojas de ruta ofrecen a los usuarios la posibilidad de adaptarse a los desarrollos futuros. Los errores en el software y las brechas de seguridad se recopilan y se reprocesan en un informe de bugs público.
- Apache HTTP server: Bug report
- NGINX: Bug report
Además del proyecto open source NGINX, Nginx, Inc. ofrece el producto comercial NGINX Plus. Mediante el pago de una tarifa anual, los usuarios disfrutan de funciones adicionales y de la asistencia profesional del fabricante. En la página oficial existe una matriz comparativa de ambos productos. No existe una versión comercial del servidor HTTP Apache, aunque hay algunos proveedores externos que ofrecen servicios de asistencia de pago.
Tanto el servidor Apache HTTP como nginx están lo suficientemente documentados como para usarse de modo profesional en sistemas productivos.
Compatibilidad y ecosistema
El servidor Apache HTTP está presente en la World Wide Web desde hace más de dos décadas y, debido a su cuota de mercado, sigue siendo el estándar de facto para la puesta a disposición de contenidos web, a pesar de que nginx también lleva una trayectoria exitosa de 15 años. Ambos servidores destacan por una amplia compatibilidad de plataformas. Mientras que Apache se recomienda para todos los sistemas operativos de tipo UNIX y Windows, la documentación de nginx indica que soporta sistemas como FreeBSD, Linux, Solaris, IBM AIX, HP-UX, macOS y Windows. Como servidor estándar, Apache destaca por su gran compatibilidad con proyectos de proveedores externos. Todos los estándares web relevantes se integran mediante módulos y a ello hay que añadir que gran parte de los agentes de Internet están familiarizados con los conceptos de Apache. Generalmente, los administradores y desarrolladores web realizan sus primeros proyectos en plataformas de alojamiento compartido de pago que se basan, en su mayoría, en Apache y permiten una configuración descentralizada vía .htaccess. Asimismo, el Apache HTTP Server es parte de un paquete de programas de código abierto de desarrollo y pruebas de software como XAMPP o AMPPS. nginx también ofrece un amplio ecosistema de módulos. Además, el equipo de desarrolladores colabora con diversos proyectos de software de código abierto y propietarios, así como con proveedores de infraestructuras como Amazon Web Services, Windows Azure y HP.
Ambos servidores web disfrutan ya de una cierta reputación y sus usuarios pueden recurrir a un amplio ecosistema. En la relación ningx vs. Apache, este último tiene la ventaja de que en los últimos años una amplia comunidad de usuarios se ha familiarizado con los fundamentos del servidor web. Debido a que miles de administradores han examinado y mejorado el código fuente del código, ya no solo se aboga por la seguridad del servidor web. Asimismo, los usuarios nuevos se benefician del gran número de administradores de Apache experimentados que asisten a la comunidad en foros o en listas de correo.
Apache vs. nginx: resumen de diferencias
A pesar de las diferencias en la arquitectura del software, ambos servidores web ofrecen funciones parecidas. Apache y nginx se utilizan en escenarios similares, pero recurren a sus propios conceptos y estrategias para estar a la altura de las exigencias. La siguiente tabla recoge las características principales de ambos proyectos de software y muestra los puntos de intersección y divergencias.
Característica | Apache | nginx |
Función | Servidor web Servidor proxy | Servidor web Servidor proxy Proxy de correo Balanceador de carga |
Lenguaje de programación | C | C |
Sistema operativo | Todas las plataformas de tipo UNIX Windows | FreeBSD Linux Solaris IBM AIX HP-UX macOS Windows |
Publicación | 1995 | 2002 |
Licencia | Apache License v2.0 | Licencia BSD (Berkeley Software Distribution) |
Desarrollador | Apache Software Foundation | Nginx, Inc. |
Arquitectura de software | Basada en procesos / hilos | Dirigida por eventos |
Concurrencia | Multiprocesamiento Multihilo | Bucle de eventos |
Contenidos web estáticos | Sí | Sí |
Contenidos web dinámicos | Sí | No |
Interpretación de las solicitudes de los clientes | Principalmente basada en archivos | Basada en URI |
Configuración | Configuración centralizada vía httpd.conf Configuración descentralizada vía .htaccess | Configuración centralizada vía nginx.conf |
Posibilidades de extensión | Módulos estáticos Módulos dinámicos | Módulos estáticos Módulos dinámicos |
Documentación | Inglés Español Francés Alemán Danés Japonés Coreano Portugués Turco Chino | Inglés Alemán |
Asistencia de los desarrolladores | No | Sí (de pago en NGINX, Inc.) |
Ayuda a la comunidad | Listas de correo Wiki | Listas de correo Wiki |
En resumen
Apache y nginx son dos proyectos open source estables y seguros, pero ninguno de los dos se erige como claro ganador y ambos se basan en decisiones diferentes de diseño que, en función de cómo se utilice el software, plantean ventajas e inconvenientes.
El servidor Apache HTTP ofrece un enorme repertorio de módulos que, junto a las flexibles posibilidades de configuración, establece numerosos campos de aplicación. Apache funciona como software estándar para escenarios de alojamiento compartido y en el futuro se impondrá en este sector de actividad frente a servidores web ligeros como nginx. La posibilidad de integrar en el servidor intérpretes para lenguajes de programación como PHP, Perl, Python o Ruby directamente a través de módulos permite la entrega de contenidos web dinámicos sin un servidor de aplicaciones separado. Esto convierte al servidor Apache HTTP en una solución cómoda para páginas de pequeña y mediana envergadura en las que los contenidos se generan de forma dinámica cuando se consultan.
Por el contrario, nginx no permite ni procesar contenidos web de un modo nativo ni integrar los intérpretes correspondientes mediante módulos y, en cualquier caso, se necesita un servidor de aplicaciones separado, lo que puede suponer un gasto adicional innecesario para las páginas web de pequeña y mediana envergadura. En los proyectos web grandes y en casos de tráfico elevado es donde se ponen de relieve los puntos fuertes de una estructura de tales características.
En general, algunos servidores de aplicaciones utilizan nginx como balanceador de carga. Este se encarga de las solicitudes entrantes y en función del tipo de requests decide si deben ser transmitidas a un servidor especializado. nginx entrega contenidos web estáticos directamente, pero si un cliente, por el contrario, solicita contenidos dinámicos, el balanceador de carga transmite la solicitud a un servidor de aplicaciones previsto para ello, el cual interpreta el lenguaje de programación, agrupa los contenidos solicitados para una página web y los devuelve al balanceador de carga, que los entrega al cliente. De este modo se pueden afrontar volúmenes de tráfico elevados. Además, nginx pone a disposición en el caché, y durante un período de tiempo determinado, contenidos ya entregados, de manera que el balanceador de carga pueda entregar de nuevo los contenidos dinámicos solicitados sin que nginx tenga que volver a recurrir a un servidor de aplicaciones.
El traslado del intérprete a uno o varios servidores de backend separados tiene la ventaja de que el conjunto de servidores puede escalarse cómodamente, incluyendo si es necesario servidores de backend adicionales o desconectando sistemas innecesarios. En la práctica, ante una arquitectura de este tipo muchos usuarios apuestan por la combinación de nginx y Apache y se valen de las fortalezas de ambos servidores web.