How To Set Up a Node.js Application for Production on Ubuntu 16.04

How To Set Up a Node.js Application for Production on Ubuntu 16.04

Node.js is an open-source JavaScript runtime environment for easily building server-side and networking applications. The platform runs on Linux, OS X, FreeBSD, and Windows. Node.js applications can be run at the command line, but for now we' ll focus on running them as a service, so that they will automatically restart on reboot or failure, and can also safely be used in a production environment.

Steps to set up a Node.js application

To install the Node.js in the system enter the download link in the teminal and press ' enter' . This command downloads the repository for installing the nodesource.

root@linuxhelp1:~# curl -sL https://deb.nodesource.com/setup_6.x -o nodesource_setup.sh

After downloading the repository file, enter the setup file command which runs the downloaded script for installing the repository in nodesource.

root@linuxhelp1:~# bash nodesource_setup.sh
## Installing the NodeSource Node.js v6.x repo...
## Populating apt-get cache...
+ apt-get update
Hit:1 http://in.archive.ubuntu.com/ubuntu xenial InRelease
Get:2 http://in.archive.ubuntu.com/ubuntu xenial-updates InRelease [102 kB]
Get:3 http://security.ubuntu.com/ubuntu xenial-security InRelease [102 kB]
Get:4 http://in.archive.ubuntu.com/ubuntu xenial-backports InRelease [102 kB]
Fetched 306 kB in 2s (116 kB/s)
Reading package lists... Done
## Confirming " xenial"  is supported...
+ curl -sLf -o /dev/null ' https://deb.nodesource.com/node_6.x/dists/xenial/Release' 
## Adding the NodeSource signing key to your keyring...
+ curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add -
OK
.
.
.
Get:4 http://security.ubuntu.com/ubuntu xenial-security InRelease [102 kB]
Get:5 https://deb.nodesource.com/node_6.x xenial/main Sources [766 B]
Get:6 http://in.archive.ubuntu.com/ubuntu xenial-backports InRelease [102 kB]
Get:7 https://deb.nodesource.com/node_6.x xenial/main amd64 Packages [960 B]
Get:8 https://deb.nodesource.com/node_6.x xenial/main i386 Packages [960 B]
Fetched 313 kB in 2s (115 kB/s)
Reading package lists... Done
## Run `apt-get install nodejs` (as root) to install Node.js v6.x and npm

The repository file is now ready and now install the nodejs software package and run the command.

root@linuxhelp1:~# apt-get install nodejs -y
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
nodejs
0 upgraded, 1 newly installed, 0 to remove and 407 not upgraded.
Need to get 10.1 MB of archives.
After this operation, 50.8 MB of additional disk space will be used.
Get:1 https://deb.nodesource.com/node_6.x xenial/main amd64 nodejs amd64 6.9.2-1nodesource1~xenial1 [10.1 MB]
Fetched 10.1 MB in 25s (397 kB/s)
Selecting previously unselected package nodejs.
(Reading database ... 176721 files and directories currently installed.)
Preparing to unpack .../nodejs_6.9.2-1nodesource1~xenial1_amd64.deb ...
Unpacking nodejs (6.9.2-1nodesource1~xenial1) ...
Processing triggers for man-db (2.7.5-1) ...
Setting up nodejs (6.9.2-1nodesource1~xenial1) ...

The installation process is now complete. Then create a node.js application.

We will write a Hello World application that simply returns " Hello World" to any HTTP requests. This is a sample application that will help you get to know whether your Node.js set up, in which you can replace with your own application just make sure that you modify your application to listen onto the appropriate IP addresses and ports.

First, create and open your Node.js application for editing. For this tutorial, we will use nano editor to edit a sample application called hello.js.

root@linuxhelp1:~# nano hello.js

Insert the following code into the file. If you want to, you may replace the highlighted port 8080 in both locations (be sure to use a non-admin port, i.e. 1024 or greater).

#!/usr/bin/env nodejs
var http = require(' http' ) 
http.createServer(function (req, res) {
  res.writeHead(200, {' Content-Type' : ' text/plain' }) 
  res.end(' Hello World
' ) 
}).listen(8080, ' localhost' ) 
console.log(' Server running at http://localhost:8080/' ) 

Now save and exit the file.

This Node.js application simply listens on the specified address (localhost) and port (8080), and returns " Hello World" with a 200 HTTP success code. Since the Node.js is listening on localhost, remote clients won' t be able to connect to our application.

Test Application

To enable the user to test the application, mark hello.js as executable file

root@linuxhelp1:~# chmod +x ./hello.js

And run it by entering the file name.

root@linuxhelp1:~# ./hello.js
Server running at http://localhost:8080/

In order to test the application, open another terminal session on your server, and connect to localhost with curl

root@linuxhelp1:~# curl http://localhost:8080
Hello World

If you do not see the proper output, make sure that your Node.js application is running, and configured to listen on the proper address and port.

Once you' re sure it' s working, kill the application (if you haven' t already) by pressing Ctrl+C.

Install PM2

Now we’ ll install PM2, which is a process manager for Node.js applications. PM2 provides an easy way to manage and daemonize applications (run them in the background as a service).

We will use npm, a package manager for Node modules that installs with Node.js, to install PM2 on our server. Use this command to install PM2.

root@linuxhelp1:~# npm install -g pm2
/usr/bin/pm2 ->  /usr/lib/node_modules/pm2/bin/pm2
/usr/bin/rundev ->  /usr/lib/node_modules/pm2/bin/rundev
/usr/bin/pm2-dev ->  /usr/lib/node_modules/pm2/bin/pm2-dev
/usr/bin/pm2-docker ->  /usr/lib/node_modules/pm2/bin/pm2-docker
/usr/lib
`-- pm2@2.2.3
  +-- async@1.5.2
  +-- chalk@1.1.3
  | +-- ansi-data-styles@2.2.1
  | +-- escape-string-regexp@1.0.5
  | +-- has-ansi@2.0.0
  | | `-- ansi-regex@2.0.0
  | +-- strip-ansi@3.0.1
  | `-- supports-color@2.0.0
  +-- chokidar@1.6.1
  | +-- anymatch@1.3.0
  | | +-- arrify@1.0.1
  | | `-- micromatch@2.3.11
  | |   +-- arr-diff@2.0.0
  | |   | `-- arr-flatten@1.0.1
  | |   +-- array-unique@0.2.1
  | |   +-- braces@1.8.5
.
.
.
  +-- shelljs@0.7.5
  | +-- glob@7.1.1
  | | +-- fs.realpath@1.0.0
  | | +-- inflight@1.0.6
  | | | `-- wrappy@1.0.2
  | | `-- once@1.4.0
  | +-- interpret@1.0.1
  | `-- rechoir@0.6.2
  |   `-- resolve@1.2.0
  +-- source-map-support@0.4.8
  | `-- source-map@0.5.6
  +-- vizion@0.2.13
  `-- yamljs@0.2.8
    `-- argparse@1.0.9
      `-- sprintf-js@1.0.3
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.0.0 (node_modules/pm2/node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.0.15: wanted {" os" :" darwin" ," arch" :" any" } (current: {" os" :" linux" ," arch" :" x64" })

The -g option tells npm to install the module globally, so that it' s available system-wide.

Manage Application with PM2

PM2 is simple and easy to use. We will cover a few basic uses of PM2.

The first thing you will want to do is use the pm2 start command to run your application, hello.js, in the background

Start Application

root@linuxhelp1:~# pm2 start hello.js
                        -------------
   Looking for a complete monitoring and management tool for PM2?
    _                             _        _            _

   | | _____ _   _ _ __ ___   ___| |_ _ __(_) ___ ___  (_) ___

   | |/ / _  | | | ' _ ` _  / _  __| ' __| |/ __/ __| | |/ _ 

   |   <   __/ |_| | | | | | |  __/ |_| |  | | (__\__ \_| | (_) |

   |_|\_\___|\__, |_| |_| |_|\___|\__|_|  |_|\___|___(_)_|\___/

             |___/

                          Features

                   - Real Time Dashboard
                   - CPU/Memory monitoring
                   - HTTP monitoring
                   - Event notification
                   - Custom value monitoring
                   - Real Time log display
                          Checkout
                   https://keymetrics.io/
                        -------------
[PM2] Spawning PM2 daemon with pm2_home=/home/user1/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /home/user1/hello.js in fork_mode (1 instance)
[PM2] Done.
???????????????????????????????????????????????????????????????????????????????????????

? App name ? id ? mode ? pid  ? status ? restart ? uptime ? cpu ? mem       ? watching ?

????????????????????????????????????????????????????????????????????????????????????????

? hello    ? 0  ? fork ? 4743 ? online ? 0       ? 0s     ? 46% ? 24.6 MB   ? disabled ?

????????????????????????????????????????????????????????????????????????????????????????
 Use `pm2 show < id|name> ` to get more details about an app

As you can see, PM2 automatically assigns an App name (based on the filename, without the .js extension) and a PM2 id. PM2 also maintains other information, such as the PID of the process, its current status, and memory usage.

Applications that are running under PM2 will be restarted automatically if the application crashes or is killed, but an additional step needs to be taken to get the application to launch on system startup (boot or reboot). Luckily, PM2 provides an easy way to do this, the startup subcommand.

The startup subcommand generates and configures a startup script to launch PM2 and its managed processes on server boots. You must also specify the platform you are running on, which is ubuntu, in our case:

root@linuxhelp1:~# pm2 startup systemd
[PM2] Init System found: systemd
Platform systemd
Template
[Unit]
Description=PM2 process manager
Documentation=https://pm2.keymetrics.io/
After=network.target
[Service]
User=root
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=8
Environment=PATH=/usr/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
Environment=PM2_HOME=/home/user1/.pm2
Restart=always
RestartSec=3
ExecStart=/usr/lib/node_modules/pm2/bin/pm2 resurrect --no-daemon
ExecReload=/usr/lib/node_modules/pm2/bin/pm2 reload all
ExecStop=/usr/lib/node_modules/pm2/bin/pm2 kill
[Install]
WantedBy=multi-user.target
.
.
.
> > >  Executing chmod +x /etc/systemd/system/pm2.service
[DONE]
> > >  Executing systemctl enable pm2
Created symlink from /etc/systemd/system/multi-user.target.wants/pm2.service to /etc/systemd/system/pm2.service.
[DONE]
> > >  Executing systemctl start pm2
[DONE]
> > >  Executing systemctl daemon-reload
[DONE]
> > >  Executing systemctl status pm2
? pm2.service - PM2 process manager
   Loaded: loaded (/etc/systemd/system/pm2.service  enabled  vendor preset: enabled)
   Active: active (running) since Fri 2016-12-30 13:30:33 IST  204ms ago
     Docs: https://pm2.keymetrics.io/
 Main PID: 4788 (node)
   CGroup: /system.slice/pm2.service

           ??4788 node /usr/lib/node_modules/pm2/bin/pm2 resurrect --no-daemon
Dec 30 13:30:33 linuxhelp1.com systemd[1]: Started PM2 process manager.
[DONE]
+---------------------------------------+
[PM2] Freeze a process list on reboot via:
$ pm2 save
[PM2] Remove init script via:
$ pm2 unstartup system

Now check the status of the pm2 service by running the following command.

root@linuxhelp1:~# systemctl status pm2
 pm2.service - PM2 process manager
   Loaded: loaded (/etc/systemd/system/pm2.service  enabled  vendor preset: enabled)
   Active: active (running) since Fri 2016-12-30 13:30:33 IST  25s ago
     Docs: https://pm2.keymetrics.io/
 Main PID: 4788 (node)
   CGroup: /system.slice/pm2.service
           ??4788 node /usr/lib/node_modules/pm2/bin/pm2 resurrect --no-daemon
Dec 30 13:30:34 linuxhelp1.com pm2[4788]: [PM2][ERROR] No processes saved  DUMP file doesn' t exist
Dec 30 13:30:34 linuxhelp1.com pm2[4788]: ????????????????????????????????????????????????????????????????????????????????????????
Dec 30 13:30:34 linuxhelp1.com pm2[4788]: ? App name ? id ? mode ? pid  ? status ? restart ? uptime ? cpu ? mem       ? watching ?
Dec 30 13:30:34 linuxhelp1.com pm2[4788]: ????????????????????????????????????????????????????????????????????????????????????????
Dec 30 13:30:34 linuxhelp1.com pm2[4788]: ? hello    ? 0  ? fork ? 4743 ? online ? 0       ? 46s    ? 0%  ? 30.5 MB   ? disabled ?
Dec 30 13:30:34 linuxhelp1.com pm2[4788]: ????????????????????????????????????????????????????????????????????????????????????????
Dec 30 13:30:34 linuxhelp1.com pm2[4788]:  Use `pm2 show < id|name> ` to get more details about an app
Dec 30 13:30:34 linuxhelp1.com pm2[4788]: [--no-daemon] Continue to stream logs
Dec 30 13:30:34 linuxhelp1.com pm2[4788]: [--no-daemon] Exit on target PM2 exit pid=4733
Dec 30 13:30:34 linuxhelp1.com pm2[4788]: [STREAMING] Now streaming realtime logs for [all] processes

Now that your Node.js application is running, and managed by PM2, let' s set up the reverse proxy.

Set Up Nginx as a Reverse Proxy Server

Now that your application is running, and listening on localhost, you need to set up a way for your users to access it. We will set up an Nginx web server as a reverse proxy for this purpose. This tutorial will set up an Nginx server from scratch. If you already have an Nginx server setup, you can just copy the location block into the server block of your choice (make sure the location does not conflict with any of your web server' s existing content).

First, install Nginx using apt-get command and press yes to continue the installation.

root@linuxhelp1:~# apt-get install nginx -y
Reading package lists... Done
Building dependency tree      
Reading state information... Done
The following additional packages will be installed:
  nginx-common nginx-core
Suggested packages:
  fcgiwrap nginx-doc
The following NEW packages will be installed:
  nginx nginx-common nginx-core
0 upgraded, 3 newly installed, 0 to remove and 407 not upgraded.
Need to get 458 kB of archives.
After this operation, 1,482 kB of additional disk space will be used.
Get:1 http://in.archive.ubuntu.com/ubuntu xenial-updates/main amd64 nginx-common all 1.10.0-0ubuntu0.16.04.4 [26.6 kB]
Get:2 http://in.archive.ubuntu.com/ubuntu xenial-updates/main amd64 nginx-core amd64 1.10.0-0ubuntu0.16.04.4 [428 kB]
.
.
.
Setting up nginx-core (1.10.0-0ubuntu0.16.04.4) ...
Setting up nginx (1.10.0-0ubuntu0.16.04.4) ...
Processing triggers for ureadahead (0.100.0-19) ...
Processing triggers for systemd (229-4ubuntu4) ...
Processing triggers for ufw (0.35-0ubuntu2) ...

Now open the default server block configuration file for editing

root@linuxhelp1:~# vim /etc/nginx/sites-available/default

Add the following lines inside the file

server {
    listen 80 
    server_name example.com 
    location / {
        proxy_pass http://localhost:8080 
        proxy_http_version 1.1 
        proxy_set_header Upgrade $http_upgrade 
        proxy_set_header Connection ' upgrade'  
        proxy_set_header Host $host 
        proxy_cache_bypass $http_upgrade 
    }
}

   location /app2 {
        proxy_pass http://localhost:8081 
        proxy_http_version 1.1 
        proxy_set_header Upgrade $http_upgrade 
        proxy_set_header Connection ' upgrade'  
        proxy_set_header Host $host 
        proxy_cache_bypass $http_upgrade 
    }

Second set of code is for add additional location blocks to the same server block to provide access to other applications on the same server. For example, if you were also running another Node.js application on port 8081.

Once you are done adding the location blocks for your applications, save and exit.

Make sure you didn' t introduce any syntax errors by typing:

root@linuxhelp1:~# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Next, permit traffic to Nginx through a firewall, if you have it enabled.

If you’ re using ufw, you can use the following command.

root@linuxhelp1:~# ufw allow ' Nginx Full' 
Rules updated
Rules updated (v6)

If you’ re using IPTables instead, you can permit traffic to Nginx by using the following command.

root@linuxhelp1:~# iptables -I INPUT -p tcp -m tcp --dport 80 -j ACCEPT

You can always check the status of your IPTables by running the following command.

root@linuxhelp1:~# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT

Assuming that your Node.js application is running, and your application and Nginx configurations are correct, you should now be able to access your application via the Nginx reverse proxy.

Tag : Node.js
FAQ
Q
What is the difference between AngularJS and Node.js?
A
Angular.JS is a web application development framework while Node.js is a runtime system.
Q
What is Node.js and how does it work?
A
Node.js is a Javascript runtime built on top of Chrome's high-performance V8 engine. Thanks to it, your JS code can run almost as fast as the one written in Java.
Q
What kind of applications can you build using Node.js?
A
Actually, you can build just about anything with Node.js, but that won’t always be a wise choice. Where Node.js excels is dealing with multiple I/O operations and real-time systems. Due to its event-based nature, it handles such cases more gracefully and much faster than other languages or frameworks.
Q
How do you update NPM to a new version in Node.js?
A
You use the following commands to update NPM to a new version:

$ sudo npm install npm -g
/usr/bin/npm -> /usr/lib/node_modules/npm/bin/npm-cli.js
npm@2.7.1 /usr/lib/node_modules/npm
Q
Explain chaining in Node.js?
A
Chaining is a mechanism whereby the output of one stream is connected to another stream creating a chain of multiple stream operations.