同一服务器上的Apache和Node.js


352

我想使用Node,因为它速度很快,使用的是我在客户端使用的相同语言,并且按照定义它是非阻塞的。但是我雇用来编写程序进行文件处理(保存,编辑,重命名,下载,上传文​​件等)的那个人,他想使用apache。因此,我必须:

  1. 说服他使用Node(在此方面他几乎没有放弃)

  2. 弄清楚如何在节点或节点中上载,下载,重命名,保存等文件

  3. 我必须在同一服务器上安装apache和node。

哪个是最有利的情况,我该如何实施?

Answers:


704

好问题!

有很多用PHP实现的网站和免费的Web应用程序都在Apache上运行,很多人都在使用它,因此您可以轻松地混合一些东西,此外,这是提供静态内容的简便方法。Node具有V8的原始功能,没有内置依赖项的扁平堆栈,是快速,强大,优雅且美观的工具。

我还希望Apache的易用性/灵活性,以及​​Node.JS的粗鲁和优雅,为什么我不能同时拥有两者

幸运的是,使用Apache中的ProxyPass指令,将httpd.conf特定URL上的所有请求通过管道传递到Node.JS应用程序并不难。

ProxyPass /node http://localhost:8000

另外,请确保未注释掉以下几行,以便您获得正确的代理和子模块来重新路由http请求:

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

然后在端口8000上运行您的Node应用程序!

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');

然后,您可以使用/node/URL上的路径访问所有Node.JS逻辑,网站的其余部分可以留给Apache托管您现有的PHP页面:

在此处输入图片说明

现在剩下的唯一事情就是说服您的托管公司让您使用此配置运行!!!


6
这是一个很好的答案,只是想添加一个链接,上面提供了我用来完成此工作的有关代理传递的更多信息。还要检查评论。boriskuzmanovic.wordpress.com/2006/10/20/…–
亚历克斯·穆罗

11
我测试了将“ ProxyPass / 127.0.0.1:8000 ”放入虚拟主机容器中,并且能够将整个域组成功重定向到节点实例。我还用“ time wget ...”进行了测试,以比较直接访问节点和通过Apache访问节点的速度。在30对试验中,平均差异约为0.56ms。直接和通过Apache的最低加载时间为120毫秒。直接加载的最高加载时间为154ms,通过Apache加载的最高时间为164ms。没有显着差异。如果我有两个IP,我不会通过Apache路由,但现在我将继续使用Proxypass
kaan_a 2014年

5
从Apache到Node的这个代理请求不是在剥夺Node非阻塞性的好处的同时呢?
追踪

2
嗨,@ Basj,我自己没有安装对websockets的支持的经验。话虽如此,Apache 2.4.6似乎支持使用代理WebSocket流量mod_proxy_wstunnel。我看现在你已经找到你的答案,对别人有同样的问题,请参见:serverfault.com/questions/616370/...
史蒂芬德萨拉斯

4
如何在基于debian的发行版中添加它?没有httpd.conf文件。
2015年

63

这个问题更多地涉及服务器故障,但是FWIW我想说在大多数情况下在Node.js之前运行Apache不是一个好方法。

Apache的ProxyPass在很多方面都很棒(例如,将基于Tomcat的服务作为站点的一部分公开),并且如果您的Node.js应用只是在做特定的,小的角色,或者是内部工具,只能容纳有限的用户数量,那么使用它可能会更容易,这样您就可以继续使用它,但这听起来不像这里。

如果您想利用性能和规模优势,可以从使用Node.js中获得收益-特别是如果您要使用涉及维护持久性连接的东西(例如Web套接字),那么最好同时运行Apache和Node。 js在其他端口上(例如localhost:8080上的Apache,localhost:3000上的Node.js),然后在前面运行类似nginx,Varnish或HA代理的内容-并以此方式路由流量。

使用诸如varnish或nginx之类的东西,您可以基于路径和/或主机来路由流量。与使用Apache进行相同的操作相比,它们都使用更少的系统资源,并且具有更大的可伸缩性。


13
这个答案应该有更多的支持。与使用Apache相比,使用nginx代理绝对是更好的方法。
rerich

是的,但是它是资源密集型的
Oracle

1
您是否有一些数字可以支持您的声明,即有关Nginx的资源密集度低于httpd的陈述?
RedShift

我不是很戏剧化。虽然我尝试不链接链接,因为链接很脆弱,但是您可以通过Google找到一些讨论和示例–例如help.dreamhost.com/hc/en-us/articles/……Apache是很棒的软件,但通常不是在这样的背景下的好方法。
伊恩·柯林斯

这个答案听起来不错,但是接下来如何通过httpS来访问Node.js,因为Apache已经采取了它?
Pierre

34


说明运行node server沿apache2(v2.4.xx) server

为了管在一个特定的URL的所有请求您的Node.js应用程序创建CUSTOM.conf的内部文件/etc/apache2/conf-available目录,并添加以下行创建的文件:

ProxyPass /node http://localhost:8000/

将8000更改为首选端口号node server
使用以下命令启用自定义配置:

$> sudo a2enconf CUSTOM

CUSTOM是您新创建的文件名,不带扩展名,然后proxy_http使用以下命令启用:

$> sudo a2enmod proxy_http

它应该同时启用proxyproxy_http模块。您可以使用以下命令检查是否启用了模块:

$> sudo a2query -m MODULE_NAME

启用配置和模块后,您将需要重新启动apache服务器:

$> sudo service apache2 restart

现在,您可以执行节点服务器。对的所有请求URL/node将由节点服务器处理。


奇迹般有效!:)
Kees Koenen

15

在一台服务器上运行Node和Apache很简单,因为它们不会冲突。NodeJS只是执行JavaScript服务器端的一种方式。真正的困境来自外部访问Node和Apache。在我看来,您有两种选择:

  1. 设置Apache以将所有匹配的请求代理到NodeJS,这将执行文件上传以及节点中的其他操作。

  2. 将Apache和Node放在不同的IP:端口组合上(如果您的服务器有两个IP,则一个可以绑定到您的节点侦听器,另一个绑定到Apache)。

我也开始怀疑这可能不是您真正想要的。如果您的最终目标是用Node.js编写应用程序逻辑,然后将某些“文件处理”部分卸载给承包商,那么这实际上是一种语言选择,而不是Web服务器。


9

您可以使用其他方法,例如用nodejs编写反向代理服务器来代理apache和所有其他nodejs应用程序。

首先,您需要使apache在端口80以外的其他端口上运行。例如:端口8080

然后,您可以使用nodejs编写反向代理脚本,如下所示:

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");

下一篇文章描述了整个过程。

使用REDBIRD与NODE JS反向代理运行APACHE



1

我将上面的答案与certbot SSL cert和CORS access-control-allow-headers结合使用,并使其起作用,所以我想我将分享结果。

Apache httpd.conf添加到文件的底部:

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

Apache VirtualHost设置(PHP的文档根目录位于Apache和Certbot的SSL下,而node.js / socket.io站点在端口3000上运行-并使用来自Apache的SSL证书)另请注意,node.js站点使用该文件夹的代理/nodejs、socket.io和ws(网络套接字):

<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>

然后是我的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});

我强制使用ip4侦听器,但这是可选的-您可以替代:

http.listen(3000);

node.js应用(app.js)代码继续:

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...
});

最后,在客户端(创建为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'
});

在此示例中,当JS加载时,它将向套接字发出一个“命名事件”,以JSON格式将数据发送到node.js / socket.io服务器。

使用服务器上的io和套接字/ pathjs(由客户端连接)下的路径,接收数据,然后将其重新发送为广播。套接字中的任何其他用户都将使用其侦听器“命名事件广播”接收数据。请注意,发件人不会收到自己的广播。


0

我最近遇到了一个类似的问题,我需要在基于PHP的codeigniter项目中使用websocket在客户端和服务器之间进行通信。

我通过将端口(正在运行的节点应用)添加到Allow incoming TCP portsAllow outgoing TCP ports列表中解决了此问题。

您可以Firewall Configurations在服务器的WHM面板中找到这些配置。


-1

我一直在寻找相同的信息。终于在@Straseus的上面答案的链接中找到了答案

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

这是在端口80上运行apache网站,在端口8080上运行node js服务并使用.htaccess RewriteRule的最终解决方案

在apache网站的DocumentRoot中,添加以下内容:

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]

对于目录级重定向,使用上面建议的(。+)规则链接,该规则在'node /'之后需要一个或多个字符。我必须将其转换为零或更大的(。*),我的东西才能正常工作。

非常感谢@Straseus的链接


3
只需注意[P]标志需要mod_proxy启用Apache 。
西蒙东

这是低效的。为什么要通过简单的调用重写引擎ProxyPass
Michael Irigoyen

-2

我假设您正在制作Web应用程序,因为您引用的是Apache和Node。快速解答-是否可以-是。是否建议-不。Node捆绑了它自己的Web服务器,大多数网站都在端口80上运行。我还假设Nodejs目前不支持Apache插件,而且我不确定创建虚拟主机是否是实现此目的的最佳方法。这些是维护Node.js的开发人员(如Joyent的好伙伴)应回答的问题。

最好不要评估端口,而要评估Node的技术堆栈,这与大多数其他端口完全不同,这就是我喜欢它的原因,但是它还涉及一些折中之处,您应该事先了解这些折衷。

您的示例看起来类似于CMS或共享Web应用程序,并且有数百种开箱即用的应用程序可以在Apache上很好地运行。即使您不喜欢任何现成的解决方案,您也可以用PHP / Java / Python编写一个Web应用程序,或者将它与几个现成的应用程序混合使用,它们的设计和支持都可以在单个Apache实例后运行。

现在是时候停下来想一想我刚才说的话了。

现在,您可以决定要使用哪个技术堆栈。如果您的网站永远不会使用数千个需要Apache的现成应用程序中的任何一个,那么请使用Node,否则您必须首先消除我之前提到的假设。

最后,您选择的技术栈比任何单个组件都重要。

我完全同意@Straseus的观点,使用node.js文件系统api来处理上传和下载是相对琐碎的,但是从长远来看,更多地考虑您想要从网站中获得什么,然后选择您的技术栈。

学习Node的框架比学习其他框架要容易,但这不是万能的。稍加努力(本身可能是值得的),您也可以学习任何其他框架。我们彼此学习,如果您是一个小型团队,则比单独工作将提高生产力,并且后端技术技能的发展也会更快。因此,请不要低估您团队中其他成员的技能。

这篇文章大约有一年的历史了,很可能您已经决定了,但是我希望我的助手能帮助下一个正在做出类似决定的人。

谢谢阅读。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.