VPS上部署 nodejs 应用并和现有应用共存
发布于 12 年前 作者 allenm 14984 次浏览 最后一次编辑是 8 年前

本文源自我的博客:http://blog.allenm.me/2012/10/deply-nodejs-with-apache/

最近,nodejs 很火,我也尝试用 nodejs 写了一个小应用,主要用到了 express framework 和 socket.io ,数据库使用的 mongodb.

我有一台Linode的VPS ,自然是想把应用部署在自己的VPS上面,为什么没有选择云服务呢?一方面是省钱,我已经为Linode付过钱了,一方面是更加自由,可以随心配置。这台Linode上已经部署了标准的 LAMP 环境,跑了几个 wordpress 。那这次部署自然是不能影响到现有应用。

我的部署方案主要要达到的目的有:

nodejs 应用可以像一个守护进程(daemon)一样运行 提供一对简单的命令来 start / stop nodejs 应用 提供监控机制,当应用崩溃,可以及时重启它 不影响现有 PHP 应用,但是也要用 80 端口访问 socket.io 提供的 websocket 功能正常使用 下面分享下我的部署经验,不一定好,我也是第一次部署,欢迎交流。

1,在 VPS 上安装 nodejs ,我 VPS 跑的是 Ubuntu 12.04 , 最简单的方式当然是通过 apt-get 来安装,但是直接 apt-get install 的话,安装的版本比较旧,建议采用 https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager 这个页面提供的方法,先添加源,再来安装,就可以安装到最新的稳定版了。这里还有其他主要 Linux 发行版的安装方式可以参考。下面的步骤默认使用的 OS 是 Ubuntu 12.04。

2,安装 mongodb (如果使用的不是 mongodb ,请忽略此步) ,http://www.mongodb.org/downloads#packages 这里同样有包管理器的安装方式,照着做就好了。

3,把你的代码放到 VPS 上来,然后以开发模式运行一次试试,不出意外的话,应该是可以运行了,如果有其他依赖需要解决,请自行解决。

4,把 nodejs 应用变成一个 daemon 。 我使用 upstart 来完成此任务 ,高版本的 ubuntu 已经自带,如果没有,直接 apt-get install upstart 来安装。然后新建一个文件在 /etc/init/yourapp.conf, 文件内容如下

#!upstart
description "node.js server"
author      "joe"

start on startup
stop on shutdown

script
    # We found $HOME is needed. Without it, we ran into problems
    export HOME="/var/www"

    echo $$ > /var/run/yourapp.pid
    exec sudo -u username NODE_ENV=production /usr/bin/node /where/yourapp.js >> /var/log/yourprogram.sys.log 2>&1
end script

pre-start script
# Date format same as (new Date()).toISOString() for consistency
    echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Starting" >> /var/log/yourapp.sys.log
end script

pre-stop script
    rm /var/run/yourprogram.pid
    echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Stopping" >> /var/log/yourapp.sys.log
end script

你需要修改上述文件的 username 为你想要运行应用的用户名,推荐 www-data ,不要使用 root ,比较危险。如果你不使用 www-data 来运行你的应用,记得把export HOME=""改成对应的 HOME 目录。/where/yourapp.js 是你应用的路径。/var/run/yourapp.pid是你应用的pid文件,/var/log/yourapp.sys.log是你应用的日志文件。这些内容都需要根据你的情况修改。NODE_ENV=production 是让你的 nodejs 应用运行在生产环境的环境变量,你可以在代码中通过 process.env.NODE_ENV来获取。

配置文件创建好后,你就可以使用下面命令来开启/关闭你的应用了。

#!sh
start yourapp
stop yourapp

5,监控你的应用。我们不能保证我们的代码总是运行的很好,总会有崩溃的可能,所以我们需要监控它的运行,当它挂掉后,重启它。这里使用 monit 来解决这个问题,安装方法自己去 http://mmonit.com/monit/ 这个网站找吧。

安装好后,新建一个文件在/etc/init/monit/conf.d/yourapp.conf,文件内容如下:

#!monit
set logfile /var/log/monit.log

check process nodejs with pidfile "/var/run/yourapp.pid"
    start program = "/sbin/start yourapp"
    stop program  = "/sbin/stop yourapp"
    if failed port 3000 protocol HTTP
        request /
        with timeout 10 seconds
        then restart

需要替换 /var/run/yourapp.pid 为你刚才设置的 pid 文件,yourapp 替换成你刚才在 upstart 设置的。port 3000 设置成你的 nodejs 应用实际监听的端口号,timeout 时间,可以根据你的实际情况调整。这几行配置文件很容易看懂,就不解释了。

然后确保 /etc/monit/monitrc 文件存在 include /etc/monit/conf.d/* 这行, 同时,你也可以在这个文件里修改监控频率,根据你的实际情况调整。然后重启 monit: service restart monit让刚才的配置文件生效。

upstart 和 monit 的配置我是参考 http://howtonode.org/deploying-node-upstart-monit 这篇博客的,你也可以来这里看看。

6,配置 apache 。我们需要在 80 端口来访问 nodejs 应用,现在又存在 apache ,那最简单的方式就使用反向代理来解决这个问题了。首先,需要安装 mod_proxy 和 mod_proxy_http ,你可以现在 /etc/apache2/mods-enabled/ 这个目录查看是否已经安装了,如果没有安装,你可以通过 a2enmod 命令来快速安装。 然后,新建一个 virtualhost ,按照你的习惯,新建一个文件 include 进去,或者一起写在某个文件。virtualhost 配置如下:

<VirtualHost *:80>
    ServerAdmin webmaster[@localhost](/user/localhost)
    ServerName yourhost.com

    ProxyRequests off

    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>

    <Location />
        ProxyPass http://localhost:3000/
        ProxyPassReverse http://localhost:3000/
    </Location>
</VirtualHost>

如果你的应用不是跑在 3000 端口上,记得修改配置, ServeName 记得改成你的域名,然后把你的域名解析到你 VPS 的 IP 上来。 ProxyPass 的作用是用 yourhost.com 来代理 localhost:3000 。ProxyPassReverse 的作用是处理 30X 跳转的情况,会把 Location:中的 http://localhost:3000 替换成 http://yourhost.com 。现在开启你的应用,重启 apache , 访问试试看。

如果都配置对了,到这里就应该能正常访问了。

使用反向代理时,要特别注意一些事情。页面中 a 标签的 url 尽量使用省略域名的形式,例如 href="/login",因为如果你处理不好,写上了 http://localhost:3000 这个后端的域名加端口,点击后就打不开了。对于 30* 跳转,Location 的值如果是 “//localhost:3000/login” 这种省略了协议的形式,apache 的反向代理也是无能为力的,我在 express 某个非正式版发现了这个问题。建议 Location 也使用省略域名的形式,这样虽然不符合 HTTP 1.1 的规范,但是各个浏览器都能兼容,可以省去这样的麻烦。

等等,如果你和我一样,也使用了 socket.io 来提供 websocket 服务,你会发现,现在长链接虽然可以用,但是却不是走 websocekt 模式了,这是因为 websocket 是无法通过 mod_proxy 来反向代理的,那就要另外想办法了。我使用的办法是:直接让 websocket 的请求去连接应用监听的后端真实端口。

7, 如果你使用了 websocket ,可以在页面中埋点,把带有你应用真实监听端口的 URI 埋入页面,然后前端 js 获取此 URI ,再来 io.connect( server ) 就可以让 websocket 正常运行了。需要注意的是,这个带端口的 URI 的域名需要和你访问页面的域名保持一致,否则取不到 cookie ,就没法获取 session 了。

如果你有更好的方式,请在下面留言交流,或者新浪微博 @allenm](http://weibo.com/allenm56) 来交流

10 回复

node有模块叫forever。可以代替楼主的upstart 和monit 那部分操作,并能给你提供日志支持。。

over~

THX , 我去看看,不过 upstart 也有日志的。

@allenm upstart记录node的报错日志么。。还有console信息。。如果可以的话,还挺好的。不过forever安装和使用比你这个教程方便太多。。install完了,直接用啥也不用配了。

@xiaojue 可以的,会记录所有打印出来的东西的。 我是刚开始玩 nodejs 的,所以对一些模块还不熟悉,下次我试试 forever

非常的好

nginx反向代理路过。

同上,使用nginx反向代理

使用 apache 是有历史原因的。这个 VPS 是和几个同事一起合租的,大家都是放放 wordpress 。最开始用过 nginx ,但是在 nginx 下,url rewirete 规则需要自己去写,没有 .htaccess 来用, wordpress 是支持自动设置 .htaccess 的。大家又懒得去折腾这些,就改用 apache 了,和 wordpress 配合的比较好。

回到顶部