How to Set Up a Node.js Application for Production with Nginx Reverse Proxy

Node.js is an open source JavaScript runtime environment for developing networking and server-side applications. It runs on OS X, Linux, FreeBSD and Windows, with applications written in JavaScript.

While Node.js applications can be run at the command line, in this tutorial we will discuss how to run them as a service, allowing it to restart automatically on reboot or in case of failure, making it conducive to be used in a production environment.

We will discuss how to set up a production-ready Node.js environment that is composed of two Ubuntu 16.04 servers, with one running Node.js applications managed by PM2, and the other providing users access to the application through a Nginx reverse proxy to the application server.

Install Node.js

To begin with, we’ll install the latest version of Node.js, using the NodeSource package archives.

$ cd ~
$ curl –sL https://deb.nodesource.com/setup_6.x -o nodesource_setup.sh

You can inspect the contents of this script with nano (or your preferred text editor):

$ nano nodesource_setup.sh

run the script under sudo:

$ sudo bash nodesource_setup.sh

The PPA will be added to your configuration. You can install the Node.js package in the same way that you did above:

$ sudo apt-get install nodejs

The Nodejs package already contains both, the Nodejs binary as well as npm, so you don’t need to install npm exclusively. However, in order for some npm packages to work (such as those that require compiling code from source), you will need to install the build-essential package:

$ sudo apt-get install build-essential

The Node.js runtime is now installed, and ready to run an application!

Create Node.js Application (Hello World Code)

This is a sample application that will help you get your Node.js set up, which you can replace with your own application

Hello World Code

Create and open your Node.js application for editing.

$ cd ~
$ vim hello.js

Insert the following code into the hello.js file.

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

We have used the 8080 port for node.js application.

Test Hello.js application

In order to test your application, mark hello.js executable:

$ chmod +x ./hello.js

And run it like so:

$ ./hello.js

Output
Server running at http://localhost:8080/

So you can access it using http://localhost:8080 and it will return “Hello World” with a 200 HTTP success code. (You can check using curl http://localhost:8080 in another ssh session if you are in cloud server)

Note: Running a Node.js application in this manner will block additional commands until the application is killed by pressing Ctrl-C.

PM2

PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks. Below are the some steps to install PM2PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks. Below are some steps to install PM2

Install PM2

We will use Node Packaged Modules (NPM), which is basically a package manager for Node modules that installs with Node.js, to install PM2 on our app server. Use this command to install PM2:

$ sudo npm install –g  pm2

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

Start Application

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

$ pm2 start hello.js

This also adds your application to PM2’s process list, which is outputted every time you start an application:

Output:
┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ hello │ 0 │ fork │ 30099 │ online │ 0 │ 0s │ 14.227 MB │ disabled │
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘

So as you 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 automatically restart if the application is killed or crashes, but there’s something else you need to do to make sure that the application launches on system startup (boot or reboot). The good thing is that with PM2, there’s 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 also need to specify the init system you are running on, which is systemd, in our case:

$ pm2 startup system (or pm2 startup ubuntu)

You should see output as follows, which indicates that the PM2 service has been installed.

Output
[PM2] Init System found: systemd
[PM2] You have to run this command as root. Execute the following command:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu

Run the command that was generated (similar to the highlighted output above, but with your username instead of ubuntu) to set PM2 up to start on boot (use the command from your own output):

$ sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu

Now your pm2-managed applications should start automatically on boot.

This will create a systemd unit which runs pm2 for your user on boot. This pm2 instance, in turn, runs hello.js. You can check the status of the systemd unit with systemctl:

$ systemctl status pm2-ubuntu

Other PM2 Usage (Optional)

PM2 provides a number of subcommands that let you manage or look up information about your applications. Note that running pm2 without any arguments will display a help page, including example usage, which covers PM2 usage in more detail than this section of the tutorial.PM2 provides a number of subcommands that let you manage or look up information about your applications. Note that running pm2 without any arguments will display a help page, including example usage, which covers PM2 usage in more detail than this section of the tutorial.Stop an application with this command (specify the PM2 App name or id):

$ pm2 stop example

Restart an application with this command (specify the PM2 App name or id):

$ pm2 restart example

The list of applications currently managed by PM2 can also be looked up with the list subcommand:

$ pm2 list

More information about a specific application can be found by using the info subcommand (specify the PM2 App name or id)

$ pm2 info example

The PM2 process monitor can be pulled up with the monit subcommand. This displays the application status, CPU, and memory usage:

$ pm2 monit

Now that your Node.js application is running, and managed by PM2,

As the node will run on some particular port number like http://yourserverip:3000 or http://yourserverip:2000. So we need to map a domain.

Time to set up the reverse proxy with Nginx

Now that your application is ready to run, and listening on localhost, It’s time to set up a way to let your users access it. For this, we will need to set up the Nginx web server as a reverse proxy.

First, we set up our Nginx configuration in the /etc/nginx/sites-available/default file. Open the file for editing:

$ sudo nano /etc/nginx/sites-available/default

You should have an existing location/block within the server block. Replace the contents of that block with the following configuration. If your application is set to listen on a different port, you can update the highlighted portion of the correct port number.

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

Doing this will configure the server to respond to requests at its root. Assuming our server is available at example.com, accessing https://example.com/ via a web browser would send the request to hello.js, listening on port 8080 at localhost.

You can 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, you could add this location block to allow access to it via http://example.com/api:

location /api {

  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;

}

Save the config and Make sure you did not introduce any syntax errors by typing:

So your nginx configuration will look like:

server {

listen 80;

server_name example.com;

 

 location /api {

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;

proxy_read_timeout 600s;

}

}

Note: This is a very basic nginx configuration example. As you can add other performance nginx values like gzip, cache and security.

$ sudo nginx –t

Time to restart the Nginx

$ sudo systemctl restart nginx

By now, you should be able to access your application via the Nginx reverse proxy. You can try it out by accessing your server’s URL (http://example.com or http://example.com/api).

Wrapping Up 

So there you have it – your own Node.js application running behind a Nginx reverse proxy on an Ubuntu 16.04 server. This particular setup offers you enough flexibility to give your users access to any other web content or applications you wish to share, Happy coding!

Checklist To Secure Your Mobile App From Every Possible Threat

Download Checklist
*We will send the checklist to your inbox and keep you updated with the latest trends and insights on app development to keep you on top of your game.
Vijay Suthar is a Passionate Network Manager who is specialized in AWS, Azure and all Cloud Technologies. He also posses expertize on Linux & Windows Web Servers, LAN & WAN Operations, Server integrations, Web Securities and Firewalls.

Leave a Reply