CopyDisable

Monday 22 June 2015

Running node.js application with Passenger and Nginx

We can use Phusion Passenger to deploy our node.js application on production, it takes out many complications that come while deploying or running Node.js application. Using Passenger is very easy and some of the benefits that we get from using Passenger are:
1) We have nginx to serve the static contents, so our app can concentrate of serving our main purpose.
2) Ngnix also protects our application from some kind of attacks.
3) Automatic restart of our application on system reboots.
4) We can run multiple Node.js applications on a single server easily.
5) Phusion Passenger can spawn more Node.js processes depending on the load etc.
6) Automatic starts a new process for a failed process.
 
First we are going to install node.js
Note: For this demo I used Ubuntu 14.04

 

Installing node.js

# curl -sL https://deb.nodesource.com/setup | sudo bash -
Now run apt-get to install node.js
# apt-get install nodejs

 

 

Installing Ngnix

# apt-get install ngnix

 

 

Installing Passenger

Install passenger PGP key.
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 561F9B9CAC40B2F7
We need to add HTTPS support for apt as passenger apt repository is hosted on an HTTPS server.
# apt-get install apt-transport-https ca-certificates
Create a file /etc/apt/sources.list.d/passenger.list and insert the following line:
# Ubuntu 14.04
deb https://oss-binaries.phusionpassenger.com/apt/passenger trusty main

Note: the above line is specifically for Ubuntu 14.04, if you are not using Ubuntu 14.04 then please refer Passenger document to get the URL for your distribution.
 
After adding the new apt source, run apt-get update followed by apt-get install
# apt-get update
# apt-get install nginx-extras passenger
 
Once passenger installation is done, edit /etc/nginx/nginx.conf and uncomment the following lines: 

passenger_root /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini;
passenger_ruby /usr/bin/passenger_free_ruby;
 
You can verify the passenger root is correct or not by the command:
# /usr/bin/passenger-config --root
 
clip_image001
 
Installation part is over, not I am going to deploy one application to test the new setup.
 
For this demo I wrote a small app test.js
 

var http = require("http");
function onRequest(request, response){
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" content="text/html; '+
'charset=UTF-8" />'+
'</head>'+
'<body>'+
'<h1>'+
'Hi I am SuperMan'+
'</h1>'+
'<img src=monkey1.gif>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type" : "text/html"});
response.write(body);
response.end();
}
http.createServer(onRequest).listen(9080);
console.log("Server has started.");
 
 
As suggested in the passenger documentation https://github.com/phusion/passenger/wiki/Phusion-Passenger%3A-Node.js-tutorial , I have created the application directory structure:
 
/apps
  |
  +-- test.js
  |
  +-- public/
  |
  +-- tmp/
 
 
/apps is the root directory of my application


test.js file is the entry point of my application. Passenger will load test.js to start my application.
 
public : This directory contains static file, so files placed in this folder will directly serve by Nginx, request will not be forwarded to the application. I copied one image file monkey1.txt in this directory.
 
tmp : We can create restart.txt file in this directory to restart the application on next request. Also this directory can be used by the application also.    
 
 
In this example I am going to run my Node.js application as my default site. So I am editing the file /etc/nginx/sites-available/default and my file looks like:
 

server {
listen 80 default_server;
listen [::]:80 default_server;
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
passenger_app_root /apps;
passenger_enabled on;
passenger_app_type node;
passenger_startup_file test.js;

#This is where my static files will go
root /apps/public;
}
 
All set, restart nginx and we are ready.
 
# service nginx restart

My superb website is up and running Smile Smile Smile
clip_image002




Friday 19 June 2015

Using PM2 process manager for node.js

 
PM2 (Process Manager 2) https://github.com/Unitech/PM2 is a process manager for Node.js applications. Some of its features are:
· PM2 allows us to run our application as multiple processes, without having to modify our application.
· It has built-in load balancing capabilities for running node.js application in cluster.
· It keeps the application up by restarting the application if it crashes.
· It can start the node application as a service when we restart the server.

 

Note: For this post I used Ubuntu 14.04

 

Installing node.js

Run the below command as root user or use sudo
# curl -sL https://deb.nodesource.com/setup | sudo bash -
clip_image002
clip_image004
Now run apt-get to install node.js
# apt-get install nodejs
clip_image006

Update 22/07/2015:
******************************************************

Suppose you want to install a different version of nodejs (at the time of writing this post the default setup was 0.10), for example suppose if I want 0.12, then go to the NodeJS github link:
https://github.com/nodesource/distributions/tree/master/deb

There you will get setup scripts for different versions of NodeJS, for my requirement of version 0.12 the script is setup_0.12, from the script get the link of the script and run the curl command:

curl -sL https://raw.githubusercontent.com/nodesource/distributions/master/deb/setup_0.12 | sudo bash -

After that run apt-get install nodejs command.

******************************************************


For testing cluster I created a small application test.js, this application shows the Process ID of the process which served the request:
For this application I need process module, install process module
clip_image008
 
My test.js file:
var http = require("http");
var process = require('process'); 

function onRequest(request, response){
response.writeHead(200, {"Content-Type" : "text/html"});
response.write('Request served by: ' + process.pid);
console.log(process.pid);
response.end();
}

http.createServer(onRequest).listen(8888);
console.log("Server has started.");
 
 
The sample output of this app:
clip_image010
 
Now I am going to install pm2 and run my test.js application using pm2.
 

Installing PM2:

$ sudo npm install pm2 -g
clip_image011

 

Running our application with pm2

Now we will start our test application using pm2 and will run multiple processes to form our cluster.
$ pm2 start test.js --name "testapp" -i 0
Options:
--name : This will specify a name for our application. This name can be used in other pm2 commands.
-i : Start the application in cluster mode, and the number of processes to run. A value of 0 informs pm2 to start as many worker processes as you have CPU cores.
clip_image013
So in our case we have 2 core CPU, so pm2 started 2 processes for our application.
 

Monitoring our application:

We can use the following pm2 commands to monitor our application:
Get list of applications monitored by pm2:
$ pm2 list
clip_image015
 
To get more details about an application:
$ pm2 show testapp
This will return details of all the processes running for that application. To get more details about a process, we can use the pm2 id for that process
$ pm2 show 1
Same output we can get using the pm2 desc command.
clip_image017
image
 
Monitoring the processes with CPU and RAM usage:
$ pm2 monit
clip_image021
The blue bar shows CPU usage and red one shows RAM usage for a particular process.
 

Checking logs of all the monitored processes:

$ pm2 logs
pm2 logs command shows tail command kind of output from all the log files. Log files for each individual processes are generated in PM2_PROCESS_USER_HOME_DIRECTORY/.pm2/logs directory.
So in my case /home/pranabs/.pm2/logs
clip_image022
clip_image024
To clean up the log files:
$ pm2 flush
clip_image025
 
To check if the cluster is working fine, I open my testapp in browser which displays the PID of the worker process which served the request.
clip_image027

clip_image029

clip_image030

If I keep refreshing the page, I could see different PIDs. If I check the displayed PIDs, I could find these PIDs in pm2 list command. This means that the user requests are being served from different processes which indicates some sort of load balancing is working in our cluster.

 


Restarting application:

pm2 reload <APP_NAME/all>
To restart all the monitored applications:
$pm2 reload all
To restart a particular application:
$pm2 reload testapp
clip_image032

 


Stopping application:

We can stop particular process/application or all applications
$ pm2 stop testapp
clip_image033

 

 

To remove application from pm2:

We can delete particular process/application or all applications from pm2
$ pm2 delete testapp
clip_image035

 

 

Checking auto start of failed process:

pm2 automatically starts a failed process. To verify that we will forcefully kill one of the processes and check whether pm2 starts another process for the failed one. Here I killed the process 5910, and we could see in the below screenshot that pm2 had started another process with ID 5939.
clip_image037

 

 

 

Starting applications automatically at server boot time

We can run the command pm2 startup to create the init script and deploy that init script to run at system startup.
To auto detect the platform just run pm2 startup:
$ pm2 startup
Also we can specify the platform with the startup command:
$ pm2 startup [platform]
The available options for platform are ubuntu, centos, redhat, gentoo, system, darwin and amazon
As I am using Ubuntu, so I am specifying ubuntu
$ pm2 startup ubuntu
This command will give us a command to run as root, which will actually deploy the init script at system startup.
sudo env PATH=$PATH:/usr/bin pm2 startup ubuntu -u pranabs
clip_image039
If we want to run the application as root, then we can directly run the pm2 startup command as root and it will deploy the necessary startup scripts.
clip_image041
Next run pm2 save command so that pm2 saves the currently monitored processes. The saved processes will be automatically started by pm2 when the system boots.
$ pm2 save
clip_image042
PM2 is very convenient tool for running node.js applications and the clustering is a very powerful feature. So try and enjoy pm2 Smile .