Nodejs in production

Last two days, I deploy a nodejs production environment on a vps. The process is hard but fun. Hence, I post this essay to note. My project is based on koa, using mongodb to store data.

As we know, when running a node application in production, we need to keep stability, performance, security, and maintainability in mind.

Begin

At begin, my initial idea is to use nginx to proxy nodejs app. And the nginx plays a Load Balancer role, improving performance and reliability by distributing the workload across multiple servers, working as a front end server. What's more, your static files can also be handled much better.

Install Node.js && MongoDB

Node.js

My vps is CentOS, the first thing we need to do is to install node.

P.S. As I use koa, so I install version 0.11.9.

$ wget http://nodejs.org/dist/v0.11.9/node-v0.11.9.tar.gz
$ tar zxvf node-v0.11.9.tar.gz
$ cd node-v0.11.9
$ ./configure
$ make
$ sudo make install

After these things done, we can check our install.

$ node -v
0.11.9
$ npm -v
1.3.15

MongoDB

For Mongo, we can follow the official installation with RedHat.

$ vim /etc/yum.repos.d/mongodb.repo

For 64-bit system, add the following information to the repo file.

[mongodb]
name=MongoDB Repository
baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64
gpgcheck=0
enabled=1

Now to install MongdoDB.

yum install mongo-10gen mongo-10gen-server

In my production, we need to open the mongod auth, edit /etc/mongod.conf to set auth=true.

And at last, we can use service mongod start or /etc/init.d/mongod start to start mongodb.:D

nginx.conf

As the idea above, we need to configure nginx.conf to proxy our app. As I'll explain, nginx is used for almost everything: gzip encoding, static file serving, HTTP caching, SSL handling, load balancing and spoon feeding clients. Here is my main nginx config:

http {
    ...
    server {
        listen 80;
        server_name reg.hduisa.cn;

        location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {
            root /home/wwwroot/reg.hduisa.cn/public;
            access_log off;
            expires max;
        }

        location / {
            proxy_pass http://127.0.0.1:3000/;
        }

        access_log /home/wwwlogs/req.hduisa.cn.log access;
    }
    ...
}

The most important part of the section is proxy_pass, this tells nginx to proxy correctly. And for static assets, any requests for with a URI starting with images, img, css, js…will be matched by this location. If you want to proxy multi apps, you can use upstream. The upstream directive specifies that these two instances work in tandem as an upstream server for nginx(not only two).

http {
    ...
    upstream reg_hduisa_cn_upstream {
        server 127.0.0.1:3000;
        server 127.0.0.1:3001;
        keepalive 64;
    }
    server {
        ...
        location / {
            proxy_pass http://reg_hduisa_cn_upstream;
        }
        ...
    }   
}

Now we can pay attention to our app. At first, we should create a user.

Create Web User

For the security of our server, we should not run the app with root. So I create a web user for my own.

$ useradd -mrU koa -p password
$ su koa

And I use pm2 to manage my app. We need install it. And for globally npm install, we can detect whether the $NODE_PATH includes the location that npm installs globally or not.

$ which node
/usr/local/bin/node
$ which npm
/usr/local/bin/npm
$ echo $NODE_PATH

My $NODE_PATH is null, so add

export NODE_PATH=/usr/local/lib/node_modules

to my .bash_profile or .zshrc. The path is not absolute, it depends on your node directory. Now we can install pm2 globally.

$ npm install pm2 -g

As my koa app needs --harmony flag, we use pm2 to start.

$ pm2 start /home/wwwroot/reg.hduisa.cn/app.js --name reg.hduisa.cn --node-args="--harmony-generators" --watch

OK, that's the whole thing, you can see the process by

$ pm2 list

End

This's my first deployment with nodejs on production, if you have something to correct, welcome to point it:D

References: