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: