How to Set up a Node.JS Application for Production Using PM2 Process Manager and Nginx as a Reverse Proxy

Okpallannuozo Nnaemeka A.
The Startup
Published in
5 min readJul 2, 2020

--

Introduction

This article provides a walk-through on how to configure a server to handle your node.js application using the PM2 process manager and Nginx as a reverse proxy server.

Prerequisites

  1. Access to an ubuntu server (In this article, we’ll be using the Ubuntu 18.04.4 LTS (Bionic Beaver)).
  2. Node.js v10.0.0 and above. The express application framework should also be ready. https://nodejs.org/en/download/
  3. Nginx installed (we’ll be using the nginx/1.14.0 ubuntu release in this article). https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/

Building the node.js application

For simplicity, a basic hello world app will be created. The app will simply return the ‘hello world’ response once a request is made to the server. To start, we create a folder in our directory with a file called ‘helloWorld.js’.

mkdir $HOME/hello
cd $HOME/HELLO && nano helloWorld.js

Next, we populate the file with a simple server script

#! /usr/bin/env nodejsconst http = require('http');http.createServer((req, res) => {res.writeHead(200, {'Content-Type': 'text/plain'});res.end('Hello World!');}).listen(4000, 'localhost');console.log('Server up and running at http://localhost:4000');

The above code simply creates a server that responds to requests with a 200 status code and content-type HTTP header. The connection ends with a ‘Hello World!’ chunk as the response. The app will listen on port 4000 using ‘localhost’ as an address. Save the file (ctrl o then enter) and exit ( ctrl x).

Executing the script

We will now have to assign an execute permission to the file, as
needed

chmod +x $HOME/hello/helloWorld.js

To run the script, simply type the following in your terminal

./hello/helloWorld.js

The output should be visible on our browser using the URL http://localhost:4000

After verifying the response, kill the application by pressing Ctrl+C on the terminal.

note:

If you do not see the response on the browser, ensure that the application is running, and configured to listen on the proper port (In this case, it’s 4000) and with the proper address (‘localhost’).

Time to install PM2

PM2 is an npm package that functions as a production process manager for Node.js applications. It comes with a built-in load balancer, allowing you to keep applications alive, and to reload them without encountering a downtime.

To install pm2 globally on your machine, simply enter the following in your terminal

sudo npm install pm2 -g

Next, we manage the app using pm2. To run your app, we simply run the following in terminal;

pm2 start helloWorld.js

The above will add your app to PM2’s process list of managed apps

Based on the output, PM2 basically assigns a name property as well as process id to the new process. In addition, information about the process status, memory, and CPU usage are included.

In order to get more details about your running app, you may use the command below:

pm2 show [id]

remember to replace id with the process id (in this case, it’s 0).

Should you choose to stop your running app, use the command below:

pm2 stop [id]

So far, we have assigned pm2 the task of maintaining our app in a running mode. How do we ensure that the app is always launched on system startup?

For this, we simply use the PM2 startup command to generate pm2’s startup script. This will be launched on system startup.

pm2 startup systemd

output:

Make sure to run the command provided in your terminal output. This will basically create a systemd unit for your PM2 process manager. With this, the systemd system service manager will always bring up your service. Next, we configure the Nginx web server as a reverse proxy.

Nginx reverse proxy configuration

In order to configure the installed Nginx server as a reverse proxy, we simply: 1. create a file in the /etc/nginx/sites-available directory

sudo nano /etc/nginx/sites-available/server

Input the following in the server file created:

server {
listen 80;
server_name server.io;
location / {
#you may replace server_name value with your
#server hostname
# e.g server_name www.server.com;
proxy_pass http://localhost:4000;
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
}
}

Basically, we are setting the server in such a way that requests coming into server.io (the server_name directive value) are directed to localhost on port 4000 (where our app is listening on).

The proxy_set_header directives are mainly used to pass vital information about the request. Also, proxy_pass specifies that the request should be forwarded to the backend server (the helloWorld app).

note:

  • Normally, the server_name directive value should be localhost since it’s our hosts local domain name. Should you choose to change it locally like I did, simply add an entry in your /etc/hosts file:
127.0.0.1 localhost
127.0.1.1 mekky-mayata
127.0.0.1 server.io # replace server.io with your desired local
# domain name
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Save the file and remember to change the server_name directive value to your chosen local domain name.

2. Create a symbolic link to the newly created file in the /etc/nginx/sites-enabled directory and reload the Nginx service for updates to take place.

cd /etc/nginx/sites-enabled
sudo ln -s /etc/nginx/sites-available/server
sudo service nginx restart

Test your setup and Voila!

Final result

review:

  • If you encounter any issues at this point, you may need to open port 4000

on your host due to system firewall.

sudo ufw allow 4000/tcp
sudo ufw reload

--

--