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

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) safelyEnable 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! 🚀




