Nginx is one of the most popular options for running high-traffic websites. Therefore, it is often used by JavaScript developers to deploy Node.js applications. Its ability to handle a large number of concurrent connections with minimal resource consumption makes it a preferred choice for modern web architectures.

In this tutorial, you will deploy a production-ready web application developed with Express.js on your Ubuntu server using Nginx. Additionally, by utilizing the cluster module, you will enable parallel execution of your application by creating worker processes that share the same server port.

1. Update packages:
sudo apt update -y
2. Install CURL:
sudo apt install curl -y
3. Install NVM:

NVM (Node Version Manager) allows us to install any Node version that we need and switch between them.

curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
4. Apply shell configuration:
source ~/.bashrc
5. Install the latest version of Node:
nvm install --lts

You can check the installed Node version with the following command.

node -v
6. Create a folder to store our application code:
mkdir /home/mydomain.com
7. Create an application:

First, we need to set up a new npm package in the application folder:

cd /home/mydomain.com
npm init -y

Then, we should install Express.js:

npm install express --save

Now, we are ready to add our application code.

Create a file named app.js and paste the javascript code below into the file:

const express = require('express')

const app = express()

app.get('/', async (req, res) => {
  res.send('Hello World!')
})

function startApp() {
  const server = app.listen(3000, () => {
    console.log(`Listening on port ${server.address().port}`);
  });
}

module.exports = { startApp };

The code block above creates a new HTTP server using Express.js with a single endpoint, allowing us to test our application once the configuration tasks are complete.

Create another file named main.js, which will be the entry point of our application, and paste the following code into it:

const cluster = require('cluster')
const os = require('os');
const { startApp } = require('./app');

const numCPUs = os.cpus().length

if (cluster.isPrimary) {
  console.log(`Master process ${process.pid} is running`);

  for (let i = 0; i < numCPUs; i++) {
    cluster.fork()
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker process ${worker.process.pid} died. Restarting...`);
    cluster.fork();
  });
} else {
  startApp()
}

We are using the cluster module to take advantage of multiple CPU cores for handling requests concurrently.

cluster is a Node.js module for creating child processes (workers) to handle load across multiple CPU cores.

os module provides operating system-related utility methods, like checking the number of CPU cores.

It retrieves the number of available CPU cores on the machine using os.cpus().length. Then, it checks if the current process is the master (primary) process using cluster.isPrimary condition. The master process is responsible for forking child worker processes. The master process creates a number of worker processes equal to the number of available CPU cores using cluster.fork(). If the process is a worker (i.e., not the master process), it creates an Express application by calling the startApp() function. So, it creates a new Express.js application for each worker process.

8. Install PM2:

pm2 is process manager for running production-ready Node.js applications. It allows us to manage and monitor our Node.js applications.

npm install -g pm2
9. Start the application:

We are ready to start our application by running the following command:

pm2 start main.js

You should see a result similar to the following in the console.

You can list all processes managed by pm2 by running the command below:

pm2 list

Our application is running. Now, we can configure Nginx to make it publicly accessible.

10. Install Nginx:
sudo apt install nginx -y 
11. Setup a server block:

We need to set up a server block (similar to virtual hosts in Apache) to serve our application.

Go to /etc/nginx/sites-available directory and edit the default file as shown below:

server {
	listen 80 default_server;
 	listen [::]:80 default_server;

	server_name mydomain.com;
	
	location / {
		proxy_pass http://127.0.0.1:3000;
		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;
	}
}

Inside the location block, we set up our proxy configuration. proxy_pass http://127.0.0.1:3000; directive passes requests to the backend server running on port 3000. It is our Node application in this case.

12. Restart Nginx:
systemctl restart nginx
Conclusion:

You can test your application by navigating to http://your-ip or http://your-domain on your browser, where you should see a "Hello World" message:

AUTHOR
PUBLISHED 12 January 2025