AWS & EC2: Deploying a Node.js application using NGINX and PM2

AWS & EC2: Deploying a Node.js application using NGINX and PM2

Introduction to AWS

AWS (Amazon Web Services) is a comprehensive, evolving cloud computing platform provided by Amazon that includes a mixture of infrastructure as a service (IaaS), platform as a service (PaaS) and packaged software as a service (SaaS) offerings. AWS services can offer an organization tools such as compute power, database storage and content delivery services.

In simple words, AWS is a secure cloud service, offering compute power, database storage and other functionalities like software and hardware dependencies for running web and application servers in the cloud providing dynamic hosting services. You can have at look at all the services provided by AWS here.

Some important terms to get started with

  • VPC => Virtual Private Cloud is a private subsection of AWS that we can control. We can have our own EC2 instances and databases in the VPC. Thus, provisioning a logically isolated section of Amazon Web Services Cloud. When we create an AWS account, a "default" VPC is created.

  • EC2 => Elastic Compute Cloud is a scalable computing capacity in AWS that eliminates the need to invest in hardware and software dependencies. EC2 allows us to launch as many or as few virtual servers as you need, configure security and networking and manage storage.

  • AMI => Amazon Machine Image provides the information required to launch an instance. It contains software configuration (OS, application servers etc.) which acts a template for instances.

  • Instances => Instances are basically virtual environments. Its configuration at launch is a copy of the AMI. Instance Type determines the hardware of the host computer used for the instance.

  • Security Group =>A security group acts as a virtual firewall for your instance to control inbound and outbound traffic. When you launch an instance in a VPC, you can assign up to five security groups to the instance.

Launching an EC2 instance and deploying a Node.js application

  • Create an AWS account ==>

Follow the steps to here to create an AWS account.

  • Sign in to your AWS management console ==> signin.png Sign in to your AWS account with your user credentials.

  • Open EC2 service ==> aws management console.png Open EC2 service on the management console - i) Select the Services dropdown. ii) Search for in the search bar. iii) Locate it in the All services list.

  • Have a look into the EC2 dashboard ==> EC2 dashboard.png Here, it will show you all the EC2 resources that are currently active and are being used.

  • Launch the EC2 instance ==>

Launch the EC2 instance by click on the Launch instance button present on the EC2 dashboard.

  • Choose an Amazon Machine Image (AMI) ==> AMI.png Select an AMI as per your use case. I have used Amazon Linux 2 AMI as it is Free tier eligible. However, there are many more AMIs from which you can choose. Now, click on Next: Choose an Instance Type.

  • Choose an Instance Type ==> Instance type.png Select an AMI as per your requirements(vCPUs, Instance storage, Memory, Network performance etc.). I have used t2.micro(its a low-cost, General Purpose Instance that provides baseline CPU performance) as it is Free tier eligible. You can have a look at various instance types here. Now click on Next: Configure Instance Details.

  • Configure Instance Details ==> Configure Instance.png Let's have a look at some of the important fields here- i) No. of instances- The no. of instances that should be launched at a time. ii) Network- We can decide that the launched instance will be launched in which VPC. iii) Subnet- A range of IP addresses in your VPC that can be used to isolate different EC2 resources from each other or from the Internet. iv) CPU options- The core count and the threads per core can be decided here. Now select Next: Add Storage.

  • Add Storage ==> Storage.png Here, we decide the device storage settings that the launched EC2 instance will use. Now click on Next: Add Tags.

  • Add Tags ==> Tags.png A tag consists of a case-sensitive key-value pair. Tags enable you to categorise your AWS resources in different ways. Now select Next: Configure Security Group.

  • Configure Security Group ==> Security group.png In this step we only configure the Inbound Traffic which by default has port 22 open that allows one to connect to EC2 via SSH. The Outbound Traffic can be configured even after the instance is launched which by default is opened to All Traffic. The Inbound Traffic can also be managed even after instance is launched. Now select Next: Review and Launch.

  • Review and Launch ==> Keyvaluepair.png While launching, a key-value pair needs to be downloaded which allows to securely SSH into the instance. Now click Launch.

  • Up and Running ==> Screenshot 2020-12-23 at 10.49.55 AM.png Screenshot 2020-12-23 at 10.50.08 AM.png Screenshot 2020-12-23 at 10.50.15 AM.png Now one can deploy application on this instance.

  • Connect to EC2 instance via SSH ==>

Locate the downloaded keyValue.pem file and run:

chmod 400 keyValue.pem
ssh -i "keyValue.pem"


  • Node.js setup ==>

Download nvm and node:

curl -o- | bash
nvm install node
node -v

You might have to reconnect to the instance if nvm command does not work.

  • Create a basic Node.js application ==>
mkdir test
cd test
npm init
npm install express
touch index.js
vim index.js


const express = require('express')
const app = express()

app.get('/', (req, res) => {
  res.send('Hello! It is running')

app.listen(3000, () => console.log('Server running on port 3000'))

Now run:

node index.js
  • Edit Inbound traffic ==> Security -> Security Groups -> Edit Inbound rules inbound.png This is done to allow traffic from port 3000.

You will now get see your output at Public IPv4 DNS of the EC2 instance: publicDNS:3000 output.png

However, we neither see nor it is encouraged to have port numbers visible in the public URL. To resolve this we will use NGINX.


NGINX will be used as a reverse proxy here. A Reverse Proxy Server, sometimes also called a reverse proxy web server, is often a feature of a load balancing solution, which stands between web servers and users, similar to a forward proxy. However, unlike the forward proxy which sits in front of users, guarding their privacy, the reverse proxy sits in front of web servers, and intercepts requests. In other words, a reverse proxy acts on behalf of the server, while a proxy acts for the client. Nginx, in front of the application server, will run on port 80 so that it can intercept all internet traffic and route it to port 3000.

Install NGINX and setup:

sudo amazon-linux-extras list | grep nginx
sudo amazon-linux-extras enable nginx1
sudo yum clean metadata
sudo yum -y install nginx
nginx -v #to ensure that nginx is installed

Start the NGINX service:

sudo systemctl start nginx

Ensure that on hitting the publuc URL of the instance you get: nginx.png

Move to nginx folder:

cd /etc/nginx
sudo vim nginx.conf

Modifications in nginx.conf inside services{...}:

location / {
                proxy_set_header  X-Real-IP  $remote_addr;
                proxy_set_header  Host       $http_host;

Restart the NGINX service:

sudo systemctl restart nginx

Now re-run the Node.js application and you will see the output of application on: publicDNS , this time without port number. output 1.png

Everything works fine as of now. But here we run into another issue. As soon as we stop the application/close the terminal we receive no output on the public URL of EC2 instance.

To resolve this we use PM2.

Using PM2

PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks. You can read more about pm2 here.

It is simple.

npm i -g pm2
pm2 start index.js
pm2 save

Now even if you stop the application/close the terminal the application is alive. output 1.png

Tip - If you are not using the EC2 instance or not only running it for practice ensure to stop the service after use to avoid bearing additional charges.

We have successfully deployed a Node.js application in conjunction with EC2 and covered any gaps that existed NGINX and PM2. In the next part, we will try to achieve Elastic Load Balancing & Auto Balancing in this deployed app.