LowEndBox - Cheap VPS, Hosting and Dedicated Server Deals

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

With this tutorial, we assume that you have already read article “How to Set Up a Node.js Application On Ubuntu 16.04 VPS”. It explains how to install a Hello World type of node.js application and how to run it locally.

Nginx is a fast and versatile web server which can be configured to serve as a reverse proxy. That will enable us to expose a Node.js app to the Internet, so that it becomes accessible from your browser. Then, we’ll secure your app by putting it behind HTTPS via Certbot – software for automating installation and configuration of the free Let’s Encrypt TLS certificates. Finally, we shall make sure that the app is running continually, by turning it into a service with a special NPM package called PM2.

What We Are Going To Cover

  • Install Nginx from a Ubuntu repository
  • Change firewall rules to enable Nginx
  • Install the latest version of node.js
  • Add NPM packages for the app that we are making
  • Create the example app to show all characters in upper case
  • Configure Nginx as a reverse proxy
  • Install Let’s Encrypt certificates to serve HTTPS requests
  • Access the app from the browser
  • Install PM2, which is a production process manager for Node.js applications with a built-in traffic Load Balancer
  • Use PM2 to restart the Node.js app on every restart or reboot of the system


We use Ubuntu 16.04:

  • Starting with a clean VPS with
  • At least 512Mb of RAM and
  • 15Gb of free disk space.
  • You will need root user access via SSH
  • A domain name pointed to your server’s IP address (it can also be a subdomain) using A records at your DNS service provider

Step 1: Install Nginx From a Repository

After you have logged in as a root user, we shall install Nginx. It is available in the default Ubuntu repositories, so let’s first refresh the cache and start the installation:

sudo apt update
sudo apt upgrade -y

It may happen that one or more packages require reconfiguration, like this:

Select the first or the second option and move on:

sudo apt install nginx -y

In the browser, go to address


and verify that Nginx is running:

Step 2: Change Firewall Rules to Enable Nginx

After the installation, we see that ufw, the uncomplicated firewall, was triggered as well:

ufw comes preinstalled on Ubuntu 16.04 and we need to configure it to allow Nginx. Let us first see what ports ufw already knows about:

sudo ufw app list

Installation of NginX added the first three options. The choices are:

  • Nginx Full: Opens ports 80 and 443 for normal, unencrypted web traffic and TLS/SSL for encrypted traffic, respectively.
  • Nginx HTTP: Only port 80 (normal, unencrypted web traffic)
  • Nginx HTTPS: Only port 443 (TLS/SSL encrypted traffic)

In theory, we should use the most restrictive type of access. However, there is a possibility that someone will use a HTTP request instead of a HTTPS, so we enable the full option:

sudo ufw allow 'Nginx Full'

Node.js apps require a port that is not used by the system, but is dedicated to that one app only. In our examples, we might use ports such as 3000, 8080 and so on, so we need to declare them explicitly, otherwise your app won’t run.

Here is a list of ports and feel free to add any other that your host requires for the normal functioning of the system:

sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw allow 20/tcp
sudo ufw allow 21/tcp
sudo ufw allow 3000
sudo ufw allow 8080
sudo ufw allow 'Nginx Full'
sudo ufw enable


If you by happen to reinstall ufw with a command such as

sudo apt install ufw

be sure to execute ufw commands with ssh, http, https and so on, otherwise you will NOT be able to log back into your VPS server!

Step 3: Install Latest Node.js

In the previous article, we explained how to install Node.js and created an app. For the sake of completness, here we give the series of commands for installation:

cd /tmp
sudo apt install curl -y
sudo curl -sLO https://deb.nodesource.com/setup_12.x
sudo bash setup_12.x
sudo apt install -y nodejs gcc g++ make
sudo nodejs -v

The script sets up the proper Ubuntu package repositories and also installs gcc, g++ and make. They may be required by some Node.js packages during their installation to compile their parts written in C or C++. Finally, it inspects the Node.js version:

Node.js version

It shows v12.3.1, which was the actual version of at the time of this writing. If it shows an error, double check the commands you entered against the ones shown above.

Step 4: Adding NPM Packages

We of course know what packages our Node.js app will need, so we install the required npm packages in advance. Since our app will turn any input into uppercase letters, we first install a package for that:

npm install upper-case

Most Node.js apps will now use Express.js, so let’s install that as well:

npm install --save express

Execute this command as well:

npm install -g nginx-generator

It will globally install an NPM package to generate the reverse proxy config for Nginx. We will apply it after the app is running on port 8080.

Step 5: Creating The App

Open a file named uppercase-http.js for editing:

nano uppercase-http.js

Add the following lines:

var http = require('http');
var uc = require('upper-case');
http.createServer(function (req, res) {
  console.log('received request for url: ' + req.url);
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write(uc(req.url + '\n'));

Save and close the file.

The HTTP server will listen to port 8080. You can specify any other port that you like, provided that it will be free when the app is running (and that you have previously opened access to it in ufw).

Run the app:

node uppercase-http.js

You will see the following message:


Node.js app starting

To test it, fire up another terminal, connect to your VPS as root via SSH and curl localhost:8080:

curl localhost:8080

The program correctly converted the path to uppercase. If you look at the server app itself, it showed a status message for both requests:

received request for url: /
received request for url: /hello

App server messages

Step 6: Configure Nginx as Reverse Proxy

Let us now empty the default file in folder /etc/nginx/sites-available/ with the following two commands:

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

Enter one space into the otherwise empty file, save and close it. The files will be created and empty, so that Nginx will read files in the /etc/nginx/sites-enabled/ folder. Now, we will use the NPM package nginx-generator that we have installed earlier in this tutorial, to generate files that will tell Nginx to act as a reverse proxy. In the command line, execute the following:

nginx-generator \
      --name site_nginx \
      --domain YOUR_DOMAIN \
      --type proxy \
      --var host=localhost \
      --var port=8080 \

Replace YOUR_DOMAIN with your domain before running this command.

That command creates a file called site_nginx and puts it into the directory /etc/nginx/sites-enabled/. We can see it with this command:

sudo nano /etc/nginx/sites-enabled/site_nginx

Test the configuration:

sudo nginx -t

and if everything is ok, restart Nginx:

systemctl restart nginx

In your browser, go to address


and the result should be


Step 7: Securing Your Site To Serve Only HTTPS

Our goal is to run a production version of a Node.js app, which means we must serve it for HTTPS requests. If you have a domain name and DNS records properly set up to point to your VPS, you can use certbot to generate Let’s Encrypt certificates. This means that you will always access the app as well as the rest of your domain, via HTTPS.

We will folow the original documentation to install Let’s Encrypt. Choose Nginx for software and Ubuntu 16.04 (xenial) for System – it should look like this:

Certbot Certbot Site

The site will then generate the following commands for you to enter into the command prompt of your VPS:

sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt update
sudo apt install certbot python-certbot-nginx 

Finally, activate it with:

sudo certbot --nginx

What certbot will ask you will depend on the previous events. If you are installing it for the fist time, it will ask for an emergency email address, then several less important questions and finally — do you want to redirect all HTTP traffic to HTTPS? Select 2 to confirm this redirection, and you’re all set!

In this case, I have been installing certbot several times, trying out different variants for this article. Therefore, it asks me to select the domain (in my case, node.duskosavic.com), then whether do I want to use the existing certificate for that domain, and only then — should it redirect HTTP to HTTPS?

To verify that redirection is working, go to the same address as previously in your browser:


Note that this address started with HTTP, but that it ended up as HTTPS.

Step 8: Install PM2

PM2 is a production process manager for Node.js applications. With PM2, we can monitor applications, their memory and CPU usage. It also provides easy commands to stop/start/restart all apps or individual apps.

Once the app is started through PM2, it will always be restarted after system crashes or restarts. In effect, it will “always be there”.

We have already installed node.js and the next step is to use NPM to install PM2:

sudo npm install pm2@latest -g

Option -g tells it install pm2 globally, meaning that we shall be able to run it from all paths in the system.

Let’s now run our application under PM2:

cd /tmp
pm2 start uppercase-http.js

The output of PM2 can be spectacular when run for the first time, but we really need to concentrate on the rows about the app:

PM2 will use app name, and then show the id number of the app, mode, status, CPU usage and memory. If two or more apps are running in the background, they will all be presented in this table.

We can list the processes like this:

sudo pm2 list

The following command

sudo pm2 show 0

will show details of the app with ID of 0:

It is also possible to monitor CPU usage in real time:

sudo pm2 monit

Other useful PM2 commands are stop, restart, delete.

What Can You Do Next

We have shown how to set up a node.js app for a production environment, as a root user. Now you can study more about Nginx and add several sites on one VPS server, each with its own non-root user, listening on different ports and so on. As a node.js programmer, you would also pay attention to debugging processes and other good practices — all of which is, however, out of scope of this article.

Dusko Savic is a technical writer and programmer.


No Comments

    Leave a Reply

    Some notes on commenting on LowEndBox:

    • Do not use LowEndBox for support issues. Go to your hosting provider and issue a ticket there. Coming here saying "my VPS is down, what do I do?!" will only have your comments removed.
    • Akismet is used for spam detection. Some comments may be held temporarily for manual approval.
    • Use <pre>...</pre> to quote the output from your terminal/console, or consider using a pastebin service.

    Your email address will not be published. Required fields are marked *