Apache y Node.js en el mismo servidor

352

Quiero usar Node porque es rápido, usa el mismo lenguaje que estoy usando en el lado del cliente y no es de bloqueo por definición. Pero el tipo que contraté para escribir el programa para el manejo de archivos (guardar, editar, renombrar, descargar, cargar archivos, etc.), quiere usar Apache. Entonces, debo:

  1. Convencerlo de usar Nodo (está cediendo poco en eso)

  2. Descubra cómo cargar, descargar, renombrar, guardar, etc. archivos en el nodo o

  3. Debo instalar Apache y el nodo en el mismo servidor.

¿Cuál es la situación más favorable y cómo la implemento?

Mate
fuente

Respuestas:

704

Gran pregunta!

Hay muchos sitios web y aplicaciones web gratuitas implementadas en PHP que se ejecutan en Apache, muchas personas lo usan para que pueda combinar algo bastante fácil y, además, es una forma sencilla de servir contenido estático. Node es una herramienta rápida, potente, elegante y sexy con la potencia bruta de V8 y una pila plana sin dependencias incorporadas.

También quiero la facilidad / flexibilidad de Apache y, sin embargo, el gruñido y la elegancia de Node.JS, ¿por qué no puedo tener ambos ?

Afortunadamente, con la directiva ProxyPass en Apache, httpd.confno es demasiado difícil canalizar todas las solicitudes en una URL particular a su aplicación Node.JS.

ProxyPass /node http://localhost:8000

Además, asegúrese de que las siguientes líneas NO estén comentadas para obtener el proxy y el submódulo correctos para redirigir las solicitudes http:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

¡Luego ejecute su aplicación Node en el puerto 8000!

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello Apache!\n');
}).listen(8000, '127.0.0.1');

Luego puede acceder a toda la lógica de Node.JS utilizando la /node/ruta en su url, el resto del sitio web puede dejarse en Apache para alojar sus páginas PHP existentes:

ingrese la descripción de la imagen aquí

¡Ahora lo único que queda es convencer a su empresa de alojamiento de que lo deje correr con esta configuración!

Steven de Salas
fuente
66
Esta fue una gran respuesta, solo quería agregar un enlace con un poco más de información sobre el pase de proxy que usé para que esto funcione. Revisa los comentarios también. boriskuzmanovic.wordpress.com/2006/10/20/…
Alex Muro
11
Probé poniendo "ProxyPass / 127.0.0.1:8000 " dentro de un contenedor de host virtual y pude redirigir con éxito un grupo de dominio completo a una instancia de nodo. También probé con "time wget ..." para comparar la velocidad de acceso al nodo directamente al acceso a través de Apache. En 30 pares de ensayos, la diferencia promedio fue de aproximadamente 0,56 ms. El tiempo de carga más bajo fue de 120 ms para ambos, directo y a través de Apache. El tiempo de carga más alto fue de 154 ms para directo y 164 a través de Apache. No es una diferencia significativa. Si tuviera el lujo de dos IPs, no enrutaría a través de Apache, pero por ahora me quedaré con Proxypass
kaan_a
55
¿Este proxy no solicita de Apache a Node, mientras le quita los beneficios de la naturaleza no bloqueante de Node?
Rastrear el
2
Hola @Basj, no tengo experiencia instalando soporte para websockets. Dicho esto, Apache 2.4.6 parece ser compatible con el proxy del tráfico de sockets web con el uso mod_proxy_wstunnel. Veo que ahora ha encontrado su respuesta, para otros con el mismo problema, consulte: serverfault.com/questions/616370/…
Steven de Salas
44
¿Dónde agrego esto en distribuciones basadas en Debian? No hay un archivo httpd.conf.
santi
63

Esta pregunta pertenece más a Server Fault, pero FWIW diría que ejecutar Apache frente a Node.js no es un buen enfoque en la mayoría de los casos.

El ProxyPass de Apache es increíble para muchas cosas (como exponer los servicios basados ​​en Tomcat como parte de un sitio) y si su aplicación Node.js solo está haciendo un pequeño rol específico o es una herramienta interna que probablemente solo tenga un número limitado de usuarios entonces podría ser más fácil usarlo para que pueda hacerlo funcionar y seguir adelante, pero eso no parece ser el caso aquí.

Si desea aprovechar el rendimiento y la escala que obtendrá al usar Node.js, y especialmente si desea usar algo que implique mantener una conexión persistente como sockets web, es mejor que ejecute tanto Apache como su nodo. js en otros puertos (por ejemplo, Apache en localhost: 8080, Node.js en localhost: 3000) y luego ejecuta algo como nginx, Varnish o proxy HA al frente, y enruta el tráfico de esa manera.

Con algo como barniz o nginx puede enrutar el tráfico en función de la ruta y / o el host. Ambos usan muchos menos recursos del sistema y son mucho más escalables que usar Apache para hacer lo mismo.

Iain Collins
fuente
13
Esta respuesta debería tener más votos a favor. Definitivamente es un enfoque mucho mejor para usar el proxy nginx que apache uno.
Rerich
Sí, pero requiere muchos recursos
Oracle
1
¿Tiene algunos números para respaldar su afirmación de que nginx consumiría menos recursos que httpd?
RedShift
No creo que sea bastante dramático. Si bien trato de no vincularme en las respuestas ya que los enlaces son frágiles, puedes encontrar algunos debates y ejemplos a través de Google, por ejemplo, help.dreamhost.com/hc/en-us/articles/… ... Apache es un gran software, pero generalmente no es un gran enfoque en un contexto como este.
Iain Collins el
Esta respuesta suena bien, pero ¿cómo acceder a Node.js a través de httpS ya que Apache ya lo ha tomado?
Pierre
34


Instrucciones para ejecutar node servera lo largo de apache2(v2.4.xx) server:

Con el fin de tubería todas las peticiones en un URL concreto para la aplicación Node.JS crear CUSTOM.confarchivo dentro /etc/apache2/conf-availabledel directorio, y añaden siguiente línea al archivo creado:

ProxyPass /node http://localhost:8000/

Cambie 8000 al número de puerto preferido para node server.
Habilite configuraciones personalizadas con el siguiente comando:

$> sudo a2enconf CUSTOM

PERSONALIZADO es su nombre de archivo recién creado sin extensión, luego habilítelo proxy_httpcon el comando:

$> sudo a2enmod proxy_http

debería habilitar ambos proxyy los proxy_httpmódulos. Puede verificar si el módulo está habilitado o no con:

$> sudo a2query -m MODULE_NAME

Después de habilitar la configuración y los módulos, deberá reiniciar el servidor apache:

$> sudo service apache2 restart

Ahora puede ejecutar el servidor de nodo. Todas las solicitudes al URL/nodeserán manejadas por el servidor de nodo.

krmld
fuente
¡Funciona de maravilla! :)
Kees Koenen
15

Ejecutar Node y Apache en un servidor es trivial ya que no entran en conflicto. NodeJS es solo una forma de ejecutar el lado del servidor JavaScript. El verdadero dilema proviene de acceder tanto a Node como a Apache desde afuera. Según lo veo, tienes dos opciones:

  1. Configure Apache para que envíe todas las solicitudes coincidentes a NodeJS, que cargará el archivo y cualquier otra cosa en el nodo.

  2. Tenga Apache y Node en diferentes IP: combinaciones de puertos (si su servidor tiene dos IP, entonces una puede estar vinculada a su escucha de nodo, la otra a Apache).

También estoy empezando a sospechar que esto podría no ser lo que realmente estás buscando. Si su objetivo final es que escriba la lógica de su aplicación en Nodejs y alguna parte de "manejo de archivos" que descargue a un contratista, entonces es realmente una elección de idioma, no un servidor web.

Yarek T
fuente
9

Puede usar un enfoque diferente, como escribir un servidor proxy inverso con nodejs para proxy tanto apache como todas las demás aplicaciones de nodejs.

Primero debe hacer que apache se ejecute en un puerto diferente que no sea el puerto 80. Ej: puerto 8080

Luego puede escribir un script proxy inverso con nodejs como:

var proxy = require('redbird')({port: 80, xfwd: false);

proxy.register("mydomain.me/blog", "http://mydomain.me:8080/blog");
proxy.register("mydomain.me", "http://mydomain.me:3000");

El siguiente artículo describe todo el proceso de hacer esto.

EJECUTE APACHE CON NODE JS REVERSE PROXY - USANDO REDBIRD

wathmal
fuente
2
ProxyPass /node http://localhost:8000/     
  • esto funcionó para mí cuando hice la entrada anterior en httpd-vhosts.conf en lugar de httpd.conf
  • Tengo XAMPP instalado en mi entorno y estaba buscando golpear todo el tráfico en Apache en el puerto 80 con la aplicación NodeJS ejecutándose en el puerto 8080, es decir, http: // localhost / [name_of_the_node_application]
rahul shukla
fuente
1

Combiné la respuesta anterior con certbot SSL cert y CORS access-control-allow-headers y lo hice funcionar, así que pensé en compartir los resultados.

Apache httpd.conf agregado al final del archivo:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Configuración de Apache VirtualHost (la raíz doc para PHP está bajo Apache y SSL con Certbot, mientras que el sitio node.js / socket.io se ejecuta en el puerto 3000 y usa el certificado SSL de Apache) También observe que el sitio node.js usa el proxy para la carpeta / nodejs, socket.io y ws (websockets):

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName www.example.com
    ServerAlias www.example.com
    DocumentRoot /var/html/www.example.com
    ErrorLog /var/html/log/error.log
    CustomLog /var/html/log/requests.log combined
    SSLCertificateFile /etc/letsencrypt/live/www.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    RewriteEngine On
    RewriteCond %{REQUEST_URI}  ^socket.io          [NC]
    RewriteCond %{QUERY_STRING} transport=websocket [NC]
    RewriteRule /{.*}       ws://localhost:3000/$1  [P,L]

    RewriteCond %{HTTP:Connection} Upgrade [NC]
    RewriteRule /(.*) ws://localhost:3000/$1 [P,L]

    ProxyPass /nodejs http://localhost:3000/
    ProxyPassReverse /nodejs http://localhost:3000/

    ProxyPass /socket.io http://localhost:3000/socket.io
    ProxyPassReverse /socket.io http://localhost:3000/socket.io

    ProxyPass /socket.io ws://localhost:3000/socket.io
    ProxyPassReverse /socket.io ws://localhost:3000/socket.io

</VirtualHost>
</IfModule>

Entonces mi aplicación node.js (app.js):

var express = require('express');
var app = express();
    app.use(function(req, res, next) {
        res.header("Access-Control-Allow-Origin", "*");
        res.header("Access-Control-Allow-Headers", "X-Requested-With");
        res.header("Access-Control-Allow-Headers", "Content-Type");
        res.header("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS");
        next();
    });
var http = require('http').Server(app);
var io = require('socket.io')(http);

http.listen({host:'0.0.0.0',port:3000});

Obligo a un oyente ip4, pero eso es opcional: puede sustituir:

http.listen(3000);

El código de la aplicación node.js (app.js) continúa con:

io.of('/nodejs').on('connection', function(socket) {
    //optional settings:
    io.set('heartbeat timeout', 3000); 
    io.set('heartbeat interval', 1000);

    //listener for when a user is added
    socket.on('add user', function(data) {
         socket.join('AnyRoomName');
         socket.broadcast.emit('user joined', data);
    });

    //listener for when a user leaves
    socket.on('remove user', function(data) {
         socket.leave('AnyRoomName');
         socket.broadcast.emit('user left', data);
    });

    //sample listener for any other function
    socket.on('named-event', function(data) {
         //code....
         socket.broadcast.emit('named-event-broadcast', data);
    });

    // add more listeners as needed... use different named-events...
});

finalmente, en el lado del cliente (creado como nodejs.js):

//notice the /nodejs path
var socket = io.connect('https://www.example.com/nodejs');

//listener for user joined
socket.on('user joined', function(data) {
    // code... data shows who joined...
});

//listener for user left
socket.on('user left', function(data) {
    // code... data shows who left...
});

// sample listener for any function:
socket.on('named-event-broadcast', function(data) {
    // this receives the broadcast data (I use json then parse and execute code)
    console.log('data1=' + data.data1);
    console.log('data2=' + data.data2);
});

// sample send broadcast json data for user joined:
socket.emit('user joined', {
    'userid': 'userid-value',
    'username':'username-value'
});

// sample send broadcast json data for user left 
//(I added the following with an event listener for 'beforeunload'):
// socket.emit('user joined', {
//     'userid': 'userid-value',
//     'username':'username-value'
// });

// sample send broadcast json data for any named-event:
socket.emit('named-event', {
    'data1': 'value1',
    'data2':'value2'
});

En este ejemplo, cuando se carga el JS, emitirá al socket un "evento con nombre" enviando los datos en JSON al servidor node.js / socket.io.

Usando el io y el socket en el servidor bajo path / nodejs (conectado por el cliente), recibe los datos y luego los reenvía como una transmisión. Cualquier otro usuario en el socket recibiría los datos con su escucha "named-event-broadcast". Tenga en cuenta que el remitente no recibe su propia transmisión.

Dr. Aaron Dishno
fuente
0

Recientemente me encontré con este tipo de problema, donde necesito comunicarme entre el cliente y el servidor usando websocket en un proyecto de codeigniter basado en PHP.

Resolví este problema agregando mi puerto (la aplicación de nodo se está ejecutando) en Allow incoming TCP ports& Allow outgoing TCP portslists.

Puede encontrar estas configuraciones en Firewall Configurationsel panel WHM de su servidor.

Paritosh Pandey
fuente
-1

Estaba buscando la misma información. Finalmente encontré la respuesta del enlace en la respuesta anterior de @Straseus

http://arguments.callee.info/2010/04/20/running-apache-and-node-js-together/

Aquí está la solución final para ejecutar el sitio web de apache en el puerto 80, el servicio del nodo js en el puerto 8080 y usar .htaccess RewriteRule

En DocumentRoot del sitio web de apache, agregue lo siguiente:

Options +FollowSymLinks -MultiViews

<IfModule mod_rewrite.c>

RewriteEngine on

# Simple URL redirect:
RewriteRule ^test.html$ http://arguments.callee.info:8000/test/ [P]

# More complicated (the user sees only "benchmark.html" in their address bar)
RewriteRule ^benchmark.html$ http://arguments.callee.info:8000/node?action=benchmark [P]

# Redirect a whole subdirectory:
RewriteRule ^node/(.*) http://arguments.callee.info:8000/$1 [P]

Para la redirección a nivel de directorio, el enlace anterior sugiere la regla (. +), Que requiere uno o más caracteres después del 'nodo /'. Tuve que convertirlo a (. *) Que es cero o más para que mis cosas funcionen.

Muchas gracias por el enlace @Straseus

pd1980
fuente
3
Solo tenga en cuenta que la bandera [P] requiere que Apache mod_proxyesté habilitado.
Simon East
Esto es ineficiente. ¿Por qué invocar el motor Rewrite sobre un simple ProxyPass?
Michael Irigoyen
-2

Supongo que está haciendo una aplicación web porque se refiere a Apache y Node. Respuesta rápida: ¿es posible? SÍ. ¿Se recomienda NO? Node agrupa su propio servidor web y la mayoría de los sitios web se ejecutan en el puerto 80. También estoy asumiendo que actualmente no hay un complemento de Apache que sea compatible con Nodejs y no estoy seguro de si crear un host virtual es la mejor manera de implementar esto. Estas son las preguntas que deben responder los desarrolladores que mantienen a Nodejs como la buena gente de Joyent.

En lugar de puertos, sería mejor evaluar la pila tecnológica de Node, que es completamente diferente de la mayoría de los demás y es por eso que me encanta, pero también implica algunos compromisos que debe tener en cuenta de antemano.

Su ejemplo es similar a un CMS o una aplicación web para compartir y hay cientos de aplicaciones listas para usar que funcionarán bien en Apache. Incluso si no le gusta ninguna solución preparada, puede escribir una aplicación web en PHP / Java / Python o mezclarla con un par de aplicaciones preparadas y todas están diseñadas y soportadas para ejecutarse detrás de una sola instancia de Apache.

Es hora de hacer una pausa y pensar en lo que acabo de decir.

Ahora está listo para decidir qué paquete tecnológico utilizará. Si su sitio web nunca usará ninguna de las miles de aplicaciones preparadas que requieren Apache, entonces vaya a Node; de ​​lo contrario, primero debe eliminar las suposiciones que dije anteriormente.

Al final, su elección de techstack es mucho más importante que cualquier componente individual.

Estoy completamente de acuerdo con @Straseus en que es relativamente trivial usar la API del sistema de archivos node.js para manejar cargas y descargas, pero piense más en lo que quiere de su sitio web a largo plazo y luego elija su techstack.

El marco de Learning Node es más fácil que aprender otros marcos, pero no es una panacea. Con un poco más de esfuerzo (que puede ser un esfuerzo valioso en sí mismo), también puede aprender cualquier otro marco. Todos aprendemos unos de otros y serás más productivo si trabajas como un equipo pequeño que si trabajas solo y tus habilidades técnicas de back-end también se desarrollarán más rápido. Por lo tanto, no descarte las habilidades de otros miembros de su equipo de manera tan económica.

Esta publicación tiene aproximadamente un año y es probable que ya lo haya decidido, pero espero que mi discurso ayude a la próxima persona que esté tomando una decisión similar.

Gracias por leer.

RHT
fuente