πŸš€ Deploying a Node.js App on AWS EC2 with PM2 and NGINX (Day 22 of #90DaysOfCloud)

Pratik DasPratik Das
4 min read

Today’s cloud journey was all about building and hosting a Node.js application from scratch on an AWS EC2 instance, without using Docker. I went from provisioning the server to configuring the application and making it available through a web browser β€” using PM2 for background processing and NGINX as a reverse proxy.

Let’s go step-by-step πŸ‘‡


☁️ Part 1: Launching the EC2 Instance

1️⃣ Go to AWS EC2 Console β†’ Launch Instance
2️⃣ Choose AMI:

  • Amazon Linux 2 (Free tier eligible)

3️⃣ Choose Instance Type:

  • t2.micro (Free tier)

4️⃣ Configure Key Pair:

  • Create or use existing key pair (e.g., my-key.pem)

5️⃣ Configure Security Group (Allow only):

  • Port 22 (SSH) β€” Your IP only

  • Port 80 (HTTP) β€” Anywhere

  • (Optional) Port 3000 β€” for direct app testing

6️⃣ Launch the instance


πŸ” Part 2: SSH into EC2 Instance

After launching:


ssh -i "my-key.pem" ec2-user@<your-ec2-public-ip>

Replace <your-ec2-public-ip> with your EC2 instance’s public IP.


🧱 Part 3: Install Node.js and NPM

Update system and install required packages:

sudo yum update -y
sudo yum install nodejs -y
sudo yum install npm -y

Verify installation:

node -v
npm -v

πŸ—‚οΈ Part 4: Create Your Node.js Application

Step 1: Create Project Directory

mkdir nodeapp
cd nodeapp

Step 2: Initialize and Create Files

Create package.json

vim package.json

Paste:

jsonCopyEdit{
  "name": "nodeapp",
  "version": "1.0.0",
  "description": "Simple Node.js App",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "^4.18.2"
  }
}

Create app.js

vim app.js

Paste:

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

app.get('/', (req, res) => {
  res.send('Hello from Node.js app on EC2!');
});

const port = 3000;
app.listen(port, () => {
  console.log(`App running on port ${port}`);
});

Step 3: Install Dependencies

npm install

🌐 Part 5: Test the Application

Run the app:

node app.js

Open browser and visit:

http://<your-ec2-public-ip>:3000

If it works, press Ctrl + C to stop it for now.


πŸ”„ Part 6: Run App in Background using PM2

Step 1: Install PM2 globally

sudo npm install -g pm2

Step 2: Start the app using PM2

pm2 start app.js

Step 3: Auto-start on reboot

pm2 startup

Follow the command it gives you (usually something like sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u ec2-user --hp /home/ec2-user)

Then run:

pm2 save

App will now persist across reboots!


🌐 Part 7: Configure NGINX as Reverse Proxy

Step 1: Install NGINX

sudo yum install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx

Step 2: Edit NGINX Config

sudo vim /etc/nginx/nginx.conf

In the server block, add this inside the location /:

location / {
    proxy_pass http://localhost:3000;
}

Example section:

server {
    listen       80;
    server_name  localhost;

    location / {
        proxy_pass http://localhost:3000;
    }
}

Step 3: Restart NGINX

sudo systemctl restart nginx

βœ… Final Result

Now you can visit:

http://<your-ec2-public-ip>

πŸŽ‰ You should see: Hello from Node.js app on EC2!


πŸ” Tips & Best Practices

  • Open only required ports in security groups (22, 80)

  • Use PM2 for production-grade Node.js app management

  • Use NGINX to proxy requests (avoid exposing port 3000)

  • Backup your key file (my-key.pem) safely

  • Enable auto-restart on reboot with pm2 startup && pm2 save


βœ… Summary

On Day 22, I learned to:

  • Launch an EC2 instance from scratch

  • Install and configure Node.js and NGINX

  • Serve an app via PM2 and expose it with a clean public URL

  • Use Linux terminal, Vim, and systemctl efficiently


πŸ“… What’s Next?

On Day 23, I’ll be deploying a Python Flask application on an EC2 instance β€” just like we did with Node.js.

πŸ”§ I’ll cover:

  • Installing Python & pip on EC2

  • Setting up a Flask web app

  • Running it in the background with Gunicorn or PM2

  • Exposing it using NGINX as a reverse proxy

  • Securing ports and handling multiple app deployments

This will strengthen my experience in hosting apps using different backends and prepare me for multi-language DevOps workflows! πŸš€

0
Subscribe to my newsletter

Read articles from Pratik Das directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Pratik Das
Pratik Das