Easy Deployment of Nodejs Applications on EC2 with PM2 and NGINX

Easy Deployment of Nodejs Applications on EC2 with PM2 and NGINX

By Pulkit6 min read
nginxpm2ec2AWSec2 instance typesEC2 instanceEc2 instance connection without public ip addinternetnetworkingNode.jsExpressnodenode jsdeploymentDeploy

Deploying Node.js applications can be a daunting task, especially when aiming for a robust and scalable production environment. However, with the right tools and a clear process, it becomes much more manageable. In this guide, I will walk you through the easy deployment of Node.js applications on Amazon EC2 using PM2 and NGINX. By the end of this article, you'll have a solid understanding of how to set up your server, manage your application processes, and configure a reverse proxy to handle incoming traffic efficiently. Let's dive in!

#Initializing the Node project

For this walkthrough, I will be deploying a simple Express hello-world application on EC2. Let's start by initialize a simple express app

npm init -y

Blog image

#Add express as a dependency

npm install express

#Adding a simple / endpoint that returns a hello world object

const express= require("express");

const app= express();

app.get("/",(req,res)=>{
  res.json({ message: "Hello world" });
});

const PORT= 3000;
app.listen(PORT,()=>{
  console.log("app is listening on port " + PORT );
});

#Start your express application

node index.js

and you see a / endpoint like this

Blog image

#Deploying the app on AWS EC2

#Let's bootstrap an EC2 instance

You can directly head over to AWS EC2 create instance page

Blog image

You can name the ec2 instance according to you, I am naming it demo-nodejs.

Blog image

Select any image that suits you best, or you can learn more about these here. I have selected the basic Ubuntu image, as it is widely used and has good support.

Blog image

Since I am using this instance for this walkthrough, I have selected a free-tier Instance type, you can choose the instance types according to your need, know more about this here

Blog image

And finally launch the instance, I am going to access this instance from AWS connect, If you want to ssh into the instance you can create a key-pair and do that

Blog image

Click on connect to access your instance and start setting up your environment.

Blog image

Now you have access to you ec2 instance from your brower

Blog image

#Setting up the Environment in the instance

Update the package lists by running:

sudo apt-get update && sudo apt-get upgrade

Installing node using the NVM(Node Version Manager)

Reference: How To Install Node.js on Ubuntu 20.04

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash

This will install the nvm script to your user account. To use it, you must first source your .bashrc file:

source ~/.bashrc

Now let's install node using the nvm

nvm install node

To check if it is installed correctly:

node --version

Blog image

#Starting the server on EC2

You can either upload your code on GitHub and then clone it in Ec2 or use any other viable method to get your code on the instance.

Blog image

If you are able to see this or whatever log you added in the app.listen() you are good to go.

#Starting the server with pm2

Now we can do a node index.js and we're good to go, but this approach has its limitations. Running your application this way means it won't automatically restart if it crashes, and it won't start again if the server reboots. This is where PM2 comes in. PM2 is a production process manager for Node.js applications that ensures your application stays online, even in the face of unexpected issues. It provides features like process monitoring, automatic restarts, and load balancing, making it an essential tool for managing Node.js applications in a production environment. Let's explore how to set up and use PM2 to manage our Node.js application on EC2.

So let's install pm2

npm install -g pm2

Now we'll start the express app using pm2

pm2 start index.js

Now we have deployed the app, but it won't be accessible on the internet yet. To make it accessible, let's configure the necessary security groups and open the required ports. This will allow external traffic to reach our application.

Blog image

Navigate to the Security tab on the Instance page. and click on the Security group which is sg-09f5337d4845d84fb (launch-wizard-1) here.

Blog image

Click on Edit inbound rules

Blog image

Add a new Inbound rue with Type of Custom TCP and PORT 3000. To make it accessible add 0.0.0.0/0 from the CIDR block.

Blog image

Now get the Ip from the home page of your instance

My Instance's Ip is ec2-54-242-52-243.compute-1.amazonaws.com, Now the app is deployed on port 300, So to access the app navigate to

http://ec2-54-242-52-243.compute-1.amazonaws.com:3000

And voilà! Your application is now accessible on the internet.

Blog image

But wait the url for the application is https://ec2-54-242-52-243.compute-1.amazonaws.com:3000, prettly ugly to add :3000 in the url. Have you ever seen we go to http://google.com:5173. No! right, So let's fix this next

#Configuring Nginx

To make your application accessible without appending the port number to the URL, we will set up NGINX as a reverse proxy. This will allow NGINX to handle incoming traffic on the default HTTP port (80) and forward it to your Node.js application running on port 3000.

#Steps to add and Install nginx

  1. Install NGINX

    First, install NGINX on your EC2 instance by running the following commands:

    sudo apt update
    sudo apt install nginx
    
  2. Start and Enable NGINX

    Ensure that NGINX is running and set to start on boot:

    sudo systemctl start nginx
    sudo systemctl enable nginx
    
  3. Configure NGINX as a Reverse Proxy

    Open the NGINX configuration file for editing:

    sudo vi /etc/nginx/sites-available/default
    

    Replace the contents of the file with the following configuration:

    server {
        listen 80;
        server_name ec2-54-242-52-243.compute-1.amazonaws.com;
    
        location / {
            proxy_pass http://localhost: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;
        }
    }
    
    1. Make sure to replace ec2-54-242-52-243.compute-1.amazonaws.com with your actual domain name or public IP address.

    2. Test the NGINX Configuration

      Test the NGINX configuration to ensure there are no syntax errors:

      sudo nginx -t
      

      If the test is successful, you should see a message indicating that the configuration file is okay.

      Blog image

    3. Restart NGINX

      Restart NGINX to apply the new configuration:

      sudo systemctl restart nginx
      
    4. Update Security Group to Allow HTTP Traffic

      Ensure that your EC2 instance's security group allows inbound traffic on port 80. Navigate to the Security Groups section in the AWS Management Console, select your instance's security group, and add a rule to allow HTTP traffic on port 80 from any IP address (0.0.0.0/0) and you may remove the 3000 port that's no more needed

    5. Access Your Application

      Now, you should be able to access your Node.js application using your domain name or public IP address without appending the port number. For example:

      http://your_domain_or_IP
      

      Your application should be accessible, and NGINX will forward the traffic to your Node.js application running on port 3000.

    Blog image

By following this guide, you have successfully deployed a Node.js application on an EC2 instance using PM2 and NGINX. This setup not only ensures that your application remains robust and scalable but also provides a clean and professional URL for your users. With PM2 managing your application processes and NGINX handling incoming traffic, you can focus on developing your application further, knowing that your deployment is in good hands. Happy coding!

Made with ❤️ by Pulkit

© 2025 Pulkit. All rights reserved

Last updated: