«Si #nginx no está delante de tu servidor Node, probablemente lo estés haciendo mal». — Bryan Hughes en Twitter
Node.js es la herramienta líder para crear aplicaciones de servidor en JavaScript, el lenguaje de programación más popular del mundo. Al ofrecer las funcionalidades tanto de un servidor web como de un servidor de aplicaciones, Node.js se considera actualmente una herramienta clave para todo tipo de desarrollo y despliegue basados en microservicios. (Descargue gratis el informe de Forrester sobre Node.js y NGINX.)
Node.js puede sustituir o complementar a Java o .NET para el desarrollo de aplicaciones backend.
Node.js utiliza un único hilo y operaciones de E/S no bloqueantes, lo que le permite escalar y admitir decenas de miles de operaciones simultáneas. Comparte estas características arquitectónicas con NGINX y resuelve el problema C10K —admitir más de 10.000 conexiones simultáneas—, para cuya resolución también se creó NGINX. Node.js es conocido por su alto rendimiento y por favorecer la productividad de los desarrolladores.
Entonces, ¿qué podría salir mal?
Node.js presenta algunos puntos débiles y vulnerabilidades que pueden hacer que los sistemas basados en Node.js sean propensos a ofrecer un rendimiento deficiente o incluso a bloquearse. Los problemas surgen con mayor frecuencia cuando una aplicación web basada en Node.js experimenta un rápido crecimiento del tráfico.
Además, Node.js es una herramienta excelente para crear y ejecutar la lógica de aplicaciones que genera el contenido principal y variable de una página web. Sin embargo, no resulta tan adecuado para servir contenido estático —como imágenes y archivos JavaScript— ni para equilibrar la carga entre varios servidores.
Para sacar el máximo partido a Node.js, es necesario almacenar en caché el contenido estático, usar un proxy y equilibrar la carga entre varios servidores de aplicaciones, así como gestionar la contención de puertos entre los clientes, Node.js y servicios auxiliares, como los servidores que ejecutan Socket.IO. NGINX puede utilizarse para todos estos fines, lo que lo convierte en una herramienta excelente para optimizar el rendimiento de Node.js.
Utiliza estos consejos para mejorar el rendimiento de las aplicaciones Node.js:
- Implementa un servidor proxy inverso
- Almacenar en caché los archivos estáticos
- Equilibrar la carga de tráfico entre varios servidores
- Intermediar conexiones WebSocket
- Implementar SSL/TLS y HTTP/2
Nota: Una solución rápida para mejorar el rendimiento de las aplicaciones Node.js consiste en modificar la configuración de Node.js para aprovechar los servidores modernos con varios núcleos. Consulta la documentación de Node.js para saber cómo hacer que Node.js genere procesos secundarios independientes, tantos como CPU tenga tu servidor web. De este modo, cada proceso se asigna casi por arte de magia a una única CPU, lo que mejora considerablemente el rendimiento.
Consejo 1 – Implementa un servidor proxy inverso
En NGINX, Inc. siempre nos horroriza un poco ver servidores de aplicaciones expuestos directamente al tráfico entrante de Internet y utilizados como núcleo de sitios de alto rendimiento. Esto incluye muchos sitios basados en WordPress, por ejemplo, así como sitios basados en Node.js.
Node.js, en mayor medida que la mayoría de los servidores de aplicaciones, está diseñado para ser escalable, y su componente de servidor web puede gestionar razonablemente bien una gran cantidad de tráfico de Internet. Sin embargo, servir contenido web no es la razón de ser de Node.js, no es para lo que realmente fue creado.
Si tienes un sitio con mucho tráfico, el primer paso para mejorar el rendimiento de la aplicación es colocar un servidor proxy inverso delante de tu servidor Node.js. Esto protege el servidor Node.js de la exposición directa al tráfico de Internet y te ofrece una gran flexibilidad para utilizar varios servidores de aplicaciones, equilibrar la carga entre ellos y almacenar contenido en caché.

Colocar NGINX delante de una configuración de servidor existente como servidor proxy inverso, además de darle otros usos, es uno de los principales casos de uso de NGINX, implementado por decenas de millones de sitios web de todo el mundo.
Usar NGINX como servidor proxy inverso para Node.js ofrece ventajas específicas, entre ellas:
- Simplificación de la gestión de privilegios y la asignación de puertos
- Servir imágenes estáticas de forma más eficiente (consulta el siguiente consejo)
- Gestionar correctamente los fallos de Node.js
- Mitigación de ataques DoS
Nota: Estos tutoriales explican cómo utilizar NGINX como servidor proxy inverso en entornos con Ubuntu 14.04 o CentOS, y ofrecen una visión general útil para cualquiera que quiera colocar NGINX delante de Node.js.
Consejo 2 – Almacena en caché los archivos estáticos
A medida que aumenta el uso de un sitio basado en Node.js, el servidor empezará a acusar la carga. Llegados a este punto, conviene hacer dos cosas:
- Sacar el máximo partido al servidor Node.js
- Facilitar la incorporación de servidores de aplicaciones y el equilibrio de carga entre ellos
En realidad, esto es fácil de hacer. Empieza por implementar NGINX como servidor proxy inverso, tal y como se describe en el consejo anterior. Esto facilita la implementación del almacenamiento en caché, el equilibrio de carga (cuando se dispone de varios servidores Node.js) y mucho más.
El sitio web de Modulus, una plataforma de contenedores de aplicaciones, incluye un artículo muy útil sobre cómo potenciar el rendimiento de las aplicaciones Node.js con NGINX. Cuando Node.js se encargaba por sí solo de todo el trabajo, el sitio del autor podía atender una media de casi 900 solicitudes por segundo. Al utilizar NGINX como servidor proxy inverso para servir contenido estático, el mismo sitio atendía más de 1600 solicitudes por segundo, lo que supone una mejora del rendimiento de casi el doble.
Duplicar el rendimiento le da tiempo para tomar medidas adicionales que permitan afrontar un mayor crecimiento, como revisar (y posiblemente mejorar) el diseño de su sitio web, optimizar el código de su aplicación e implementar servidores de aplicaciones adicionales.
A continuación se muestra el código de configuración que funciona para un sitio web alojado en Modulus:
server { listen 80;
server_name static-test-47242.onmodulus.net;
root /mnt/app;
index index.html index.htm;
location /static/ {
try_files $uri $uri/ =404;
}
location /api/ {
proxy_pass http://node-test-45750.onmodulus.net;
}
}Este detallado artículo de Patrick Nommensen, de NGINX, Inc., explica cómo almacena en caché el contenido estático de su blog personal, que utiliza Ghost, una plataforma de blogs de código abierto y una aplicación Node.js. Aunque algunos detalles son específicos de Ghost, gran parte del código puede reutilizarse en otras aplicaciones Node.js.
Por ejemplo, en el bloque location de NGINX, probablemente querrá excluir cierto contenido del almacenamiento en caché. Normalmente no conviene almacenar en caché la interfaz de administración de una plataforma de blogs. Este es el código de configuración que desactiva (o excluye) el almacenamiento en caché de la interfaz de administración de Ghost:
location ~ ^/(?:ghost|signout) { proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://ghost_upstream;
add_header Cache-Control "no-cache, private, no-store,
must-revalidate, max-stale=0, post-check=0, pre-check=0";
}Para obtener información general sobre cómo servir contenido estático, consulte la Guía de administración de NGINX Plus. La Guía de administración incluye instrucciones de configuración, varias opciones para responder a los intentos correctos o fallidos de encontrar un archivo y métodos de optimización para lograr un rendimiento aún mayor.
El almacenamiento en caché de archivos estáticos en el servidor NGINX reduce considerablemente la carga de trabajo del servidor de aplicaciones Node.js, lo que permite alcanzar un rendimiento mucho mayor.
Consejo 3 – Implemente un balanceador de carga de Node.js
La verdadera clave para lograr un alto rendimiento —es decir, prácticamente ilimitado— en las aplicaciones Node.js consiste en ejecutar varios servidores de aplicaciones y equilibrar la carga entre todos ellos.
El balanceo de carga de Node.js puede resultar especialmente complejo, ya que Node.js permite un alto grado de interacción entre el código JavaScript que se ejecuta en el navegador web y el que se ejecuta en el servidor de aplicaciones Node.js, utilizando objetos JSON como medio de intercambio de datos. Esto implica que una determinada sesión de cliente se ejecuta de forma continua en un servidor de aplicaciones específico, y que mantener la persistencia de la sesión resulta intrínsecamente difícil cuando se utilizan varios servidores de aplicaciones.
Una de las principales ventajas de Internet y la web es su elevado grado de ausencia de estado, que permite que las solicitudes de los clientes sean atendidas por cualquier servidor que tenga acceso al archivo solicitado. Node.js rompe con este modelo sin estado y funciona mejor en un entorno con estado, donde el mismo servidor responde sistemáticamente a las solicitudes de cada cliente concreto.
Este requisito se puede satisfacer mejor con NGINX Plus, en lugar de NGINX Open Source. Las dos versiones de NGINX son bastante similares, pero una diferencia importante es la compatibilidad con distintos algoritmos de balanceo de carga.
NGINX admite métodos de balanceo de carga sin estado:
- Round Robin – Cada nueva solicitud se envía al siguiente servidor de la lista.
- Menor número de conexiones – Las nuevas solicitudes se envían al servidor que tenga menos conexiones activas.
- Hash de IP – Una nueva solicitud se dirige al servidor asignado al hash de la dirección IP del cliente.
Solo uno de estos métodos, IP Hash, envía de forma fiable las solicitudes de un cliente determinado al mismo servidor, lo que beneficia a las aplicaciones Node.js. Sin embargo, IP Hash puede hacer fácilmente que un servidor reciba un número desproporcionado de solicitudes en detrimento de otros servidores, como se describe en esta entrada de blog sobre técnicas de balanceo de carga. Este método permite mantener el estado, aunque puede dar lugar a una distribución poco óptima de las solicitudes entre los recursos de los servidores.
A diferencia de NGINX, NGINX Plus admite la persistencia de sesión. Cuando se utiliza la persistencia de sesión, el mismo servidor recibe de forma fiable todas las solicitudes de un cliente determinado. De este modo, se aprovechan al máximo tanto las ventajas de Node.js, con su comunicación con estado entre el cliente y el servidor, como las de NGINX Plus, con su avanzada capacidad de equilibrio de carga.
Por tanto, puede utilizar NGINX o NGINX Plus para distribuir la carga entre varios servidores Node.js. Sin embargo, solo con NGINX Plus podrá conseguir tanto el máximo rendimiento del balanceo de carga como una gestión del estado compatible con Node.js. Las comprobaciones del estado de las aplicaciones y las funciones de monitorización integradas en NGINX Plus también resultan útiles en este caso.
NGINX Plus también admite el vaciado de sesiones, que permite a un servidor de aplicaciones completar correctamente las sesiones actuales después de solicitar que el servidor se retire del servicio.
Consejo 4: conexiones proxy WebSocket
HTTP, en todas sus versiones, está diseñado para comunicaciones de tipo «pull», en las que el cliente solicita archivos al servidor. WebSocket es una herramienta que permite comunicaciones de tipo «push» y «push/pull», en las que el servidor puede enviar de forma proactiva archivos que el cliente no ha solicitado.
El protocolo WebSocket facilita una interacción más sólida entre el cliente y el servidor, al tiempo que reduce la cantidad de datos transferidos y minimiza la latencia. Cuando es necesario, se puede establecer una conexión dúplex completa en la que tanto el cliente como el servidor inicien y reciban solicitudes según sea necesario.
El protocolo WebSocket cuenta con una sólida interfaz de JavaScript, por lo que encaja de forma natural con Node.js como servidor de aplicaciones y, en el caso de aplicaciones web con un volumen moderado de transacciones, también como servidor web. Cuando aumenta el volumen de transacciones, conviene intercalar NGINX entre los clientes y el servidor web Node.js, utilizando NGINX o NGINX Plus para almacenar en caché los archivos estáticos y distribuir la carga entre varios servidores de aplicaciones.
Node.js se utiliza a menudo junto con Socket.IO, una API de WebSocket que se ha popularizado bastante para su uso con aplicaciones Node.js. Esto puede provocar que el puerto 80 (para HTTP) o el puerto 443 (para HTTPS) se saturen, y la solución consiste en utilizar un proxy para el servidor Socket.IO. Puede utilizar NGINX como servidor proxy, tal como se ha descrito anteriormente, y obtener además funcionalidades adicionales como el almacenamiento en caché de archivos estáticos, el balanceo de carga y mucho más.

A continuación se muestra el código de un archivo de aplicación Node server.js que escucha en el puerto 5000. Actúa como servidor proxy (no como servidor web) y dirige las solicitudes al puerto correspondiente:
var io = require('socket.io').listen(5000);
io.sockets.on('connection', function (socket) {
socket.on('set nickname', function (name) {
socket.set('nickname', name, function () {
socket.emit('ready');
});
});
socket.on('msg', function () {
socket.get('nickname', function (err, name) {
console.log('Chat message by ', name);
});
});
});En el archivo index.html, añade el siguiente código para conectarte a la aplicación del servidor y crear un WebSocket entre la aplicación y el navegador del usuario:
<script src="/socket.io/socket.io.js"></script><script>// <![CDATA[
var socket = io(); // your initialization code here.
// ]]>
</script>Para obtener instrucciones completas, incluida la configuración de NGINX, consulte nuestra entrada del blog sobre el uso de NGINX y NGINX Plus con Node.js y Socket.IO. Para profundizar en los posibles problemas de arquitectura e infraestructura de este tipo de aplicaciones web, consulte nuestra entrada del blog sobre aplicaciones web en tiempo real y WebSocket.
Consejo 5 – Implemente SSL/TLS y HTTP/2
Cada vez más sitios utilizan SSL/TLS para proteger todas las interacciones de los usuarios en el sitio. Usted decide si desea dar este paso y cuándo hacerlo, pero, si finalmente lo hace, NGINX facilita la transición de dos maneras:
- Puede finalizar una conexión SSL/TLS con el cliente en NGINX una vez que haya configurado NGINX como proxy inverso. El servidor Node.js intercambia solicitudes y contenido sin cifrar con el servidor proxy inverso NGINX.
- Los primeros indicios apuntan a que el uso de HTTP/2, la nueva versión del protocolo HTTP, puede compensar en gran medida o por completo la pérdida de rendimiento que, de otro modo, conlleva el uso de SSL/TLS. NGINX es compatible con HTTP/2 y permite terminar HTTP/2 junto con SSL/TLS, lo que, una vez más, elimina la necesidad de realizar cambios en los servidores de aplicaciones Node.js.
Entre los pasos de implementación que debe llevar a cabo se incluyen actualizar la URL en el archivo de configuración de Node.js, establecer y optimizar conexiones seguras en la configuración de NGINX y, si lo desea, utilizar SPDY o HTTP/2. Al añadir compatibilidad con HTTP/2, las versiones de los navegadores que admiten HTTP/2 se comunican con su aplicación mediante el nuevo protocolo, mientras que las versiones anteriores siguen utilizando HTTP/1.x.

El siguiente código de configuración corresponde a un blog de Ghost que utiliza SPDY, tal como se describe aquí. Incluye funciones avanzadas como el grapado OCSP. Para obtener información sobre el uso de NGINX para la terminación SSL, incluida la opción de grapado OCSP, consulta aquí. Para obtener una visión general de estos mismos temas, consulta aquí.
Solo tiene que realizar pequeños cambios para configurar su aplicación Node.js y actualizar de SPDY a HTTP/2, ya sea ahora o cuando deje de ofrecerse compatibilidad con SPDY a principios de 2016.
server { server_name domain.com;
listen 443 ssl spdy;
spdy_headers_comp 6;
spdy_keepalive_timeout 300;
keepalive_timeout 300;
ssl_certificate_key /etc/nginx/ssl/domain.key;
ssl_certificate /etc/nginx/ssl/domain.crt;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 24h;
ssl_buffer_size 1400;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/ssl/trust.crt;
resolver 8.8.8.8 8.8.4.4 valid=300s;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';
add_header X-Cache $upstream_cache_status;
location / {
proxy_cache STATIC;
proxy_cache_valid 200 30m;
proxy_cache_valid 404 1m;
proxy_pass http://ghost_upstream;
proxy_ignore_headers X-Accel-Expires Expires Cache-Control;
proxy_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;
proxy_hide_header X-powered-by;
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 https;
proxy_set_header Host $http_host;
expires 10m;
}
location /content/images {
alias /path/to/ghost/content/images;
access_log off;
expires max;
}
location /assets {
alias /path/to/ghost/themes/uno-master/assets;
access_log off;
expires max;
}
location /public {
alias /path/to/ghost/built/public;
access_log off;
expires max;
}
location /ghost/scripts {
alias /path/to/ghost/core/built/scripts;
access_log off;
expires max;
}
location ~ ^/(?:ghost|signout) {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://ghost_upstream;
add_header Cache-Control "no-cache, private, no-store,
must-revalidate, max-stale=0, post-check=0, pre-check=0";
proxy_set_header X-Forwarded-Proto https;
}
}
Conclusión
Esta entrada de blog describe algunas de las mejoras de rendimiento más importantes que puede implementar en sus aplicaciones Node.js. Se centra en incorporar NGINX a su conjunto de aplicaciones junto con Node.js: utilizando NGINX como servidor proxy inverso, para almacenar en caché archivos estáticos, equilibrar la carga, actuar como proxy de conexiones WebSocket y terminar los protocolos SSL/TLS y HTTP/2.
La combinación de NGINX y Node.js está ampliamente reconocida como una forma de crear nuevas aplicaciones compatibles con microservicios o de aportar flexibilidad y funcionalidad a las aplicaciones existentes basadas en SOA que utilizan Java o Microsoft .NET. Este artículo le ayuda a optimizar sus aplicaciones Node.js y, si así lo desea, a hacer realidad la colaboración entre Node.js y NGINX.
Sobre el autor

Artículos relacionados del blog
Únete a F5 NGINX en AppWorld 2024
Descubre las numerosas razones para asistir al evento insignia de F5, que incluirá un emocionante anuncio sobre la cartera de productos NGINX.
Rotación de certificados SSL/TLS sin reinicios en NGINX Open Source
La función de diccionario compartido permite configurar NGINX sin necesidad de reiniciarlo al renovar los certificados SSL/TLS.
Exposición de APIs en Kubernetes
La unidad 2 de Microservices March 2022 se centra en cómo exponer tus API en Kubernetes. Aquí tienes enlaces a los recursos que necesitas: la retransmisión en directo del 14 de marzo, artículos de blog y otros recursos de preparación, y el laboratorio práctico «Protege las API de Kubernetes mediante la limitación de solicitudes».
NGINX Sprint 2.0: visión clara, código renovado y nuevos compromisos con el código abierto
Hoy, en NGINX Sprint 2.0, anunciamos cómo respaldaremos nuestra visión del futuro de las aplicaciones modernas con una mayor presencia en la comunidad de código abierto, incluida la participación en el proyecto comunitario Kubernetes, nuevos proyectos de software de código abierto y la arquitectura de referencia para aplicaciones modernas.
Presentamos NGINX Plus R22
NGINX Plus R22 incorpora nuevas funcionalidades, como la compatibilidad con OCSP para verificar la revocación de certificados en TLS mutuo, el uso de varios proveedores de identidad OIDC en una configuración, el seguimiento en tiempo real de la limitación de solicitudes y conexiones en el panel de NGINX Plus y mejoras en NGINX JavaScript.
Presentamos NGINX Plus R17
NGINX Plus R17 incorpora compatibilidad con la limitación de velocidad en dos fases y con TLS 1.3, la versión más reciente del protocolo Transport Layer Security. La configuración de OpenID Connect es más sencilla y NGINX ModSecurity WAF es el doble de rápido que antes. También se ha actualizado el módulo JavaScript de NGINX.