Coding Dimension Logo
CodingDimension
DevOps

Complete AWS EC2 Ubuntu Deployment Guide (Node.js + PM2 + Nginx)

Published
Aug 11, 2026
Reading Time
15 min read

Admin

Author

Deploy a Node.js/Express backend on AWS EC2 Ubuntu: install Node, clone the repo, configure .env, run with PM2, and put Nginx in front with a firewall checklist.

Overview

Deploy a Node.js / Express backend on an AWS EC2 Ubuntu instance using PM2 and Nginx as a reverse proxy. Follow the sections in order the first time; later use the command reference when something breaks.

1. Connect to EC2

ssh -i your-key.pem ubuntu@YOUR_SERVER_IP

Example:

ssh -i myserver.pem ubuntu@13.126.xxx.xxx
  • Exit server: exit
  • Switch to root (optional): sudo su
  • Current user: whoami
  • Current directory: pwd

2. Update Ubuntu

sudo apt update
sudo apt upgrade -y
sudo apt autoremove -y
sudo apt clean

3. Install Git

sudo apt install git -y
git --version

git config --global user.name "Your Name"
git config --global user.email "your-email@example.com"
git config --list
which git

4. Install Node.js (LTS)

sudo apt install curl -y
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install nodejs -y

node -v
npm -v
which node
which npm

5. Clone the repository

# HTTPS
git clone https://github.com/username/project.git

# SSH
git clone git@github.com:username/project.git

cd project
git branch
git pull origin main

6. Environment variables

nano .env

Example .env:

PORT=5000
DATABASE_URL=
JWT_SECRET=
REDIS_URL=
AWS_ACCESS_KEY=
AWS_SECRET_KEY=

In nano: Ctrl+O, Enter, Ctrl+X. Verify with cat .env and ls -la.

7. Install dependencies

npm install

# Clean install if needed
rm -rf node_modules package-lock.json
npm install

8. Build the project

# TypeScript
npm run build

# Prisma (if used)
npx prisma generate
npx prisma migrate deploy
npm run seed

9. Test the app

npm run dev      # development
npm start        # production (often node dist/server.js)

9.1 Install Redis (optional)

sudo apt install redis-server -y

9.2 Install MongoDB (optional)

Server packages

curl -fsSL https://pgp.mongodb.com/server-8.0.asc | \\
  sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor

echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | \\
  sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list

sudo apt update
sudo apt install -y mongodb-org
mongod --version

Start and enable

sudo systemctl start mongod
sudo systemctl enable mongod
sudo systemctl status mongod

Expected: Active: active (running).

Kernel compatibility override (if needed)

sudo systemctl edit mongod

Add:

[Service]
Environment="MONGODB_DISABLE_KERNEL_VERSION_CHECK=true"
sudo systemctl daemon-reload
sudo systemctl restart mongod
sudo systemctl status mongod

Logs and shell

sudo journalctl -u mongod -n 50 --no-pager
sudo tail -50 /var/log/mongodb/mongod.log

sudo apt install mongodb-mongosh
mongosh

MongoDB Compass is a GUI — it needs a desktop display. On a headless EC2 box, use mongosh instead of Compass.

10. Install and run with PM2

sudo npm install -g pm2
pm2 -v

pm2 start npm --name backend -- start
# or
pm2 start dist/server.js --name backend

11. Essential PM2 commands

pm2 list
pm2 logs
pm2 logs backend
pm2 restart backend
pm2 reload backend
pm2 stop backend
pm2 delete backend
pm2 monit
pm2 save
pm2 startup
# run the command PM2 prints, then:
pm2 save

12. Install Nginx

sudo apt install nginx -y
sudo systemctl status nginx
sudo systemctl start nginx
sudo systemctl enable nginx
sudo systemctl restart nginx
sudo systemctl reload nginx

13. Nginx reverse proxy

sudo nano /etc/nginx/sites-available/backend
server {
    listen 80;
    server_name YOUR_SERVER_IP;

    location / {
        proxy_pass http://localhost:5000;
        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;
    }
}
sudo ln -s /etc/nginx/sites-available/backend /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

14. Firewall (UFW)

sudo apt install ufw -y
sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable
sudo ufw status

15. Useful Ubuntu commands

pwd
ls
ls -la
cd foldername
cd ..
cd ~
cd /
mkdir folder
rm -rf folder
rm file.txt
mv old new
cp file file2

16. Disk, memory, and CPU

df -h
du -sh *
free -h
lscpu

17. Processes and ports

ps aux
ps aux | grep node
kill PID
kill -9 PID

sudo ss -tulpn
sudo lsof -i :5000
sudo kill -9 PID

18. Logs

pm2 logs
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
journalctl -xe

19. Git on the server

git status
git pull
git fetch
git branch
git checkout main
git log --oneline

20. Node / npm helpers

node -v
npm -v
npm list -g --depth=0
npm cache clean --force

21. Service status

systemctl status nginx
systemctl status ssh
systemctl status docker
sudo systemctl restart nginx

22. Common errors and fixes

Port already in use

sudo lsof -i :5000
sudo kill -9 PID

Node not found

which node
node -v
sudo apt install nodejs -y

Git permission denied

ssh-keygen -t ed25519 -C "your@email.com"
cat ~/.ssh/id_ed25519.pub

Add the public key to GitHub, then clone over SSH again.

PM2 not found

sudo npm install -g pm2

Nginx config test

sudo nginx -t

Reboot / shutdown

sudo reboot
sudo shutdown now

Deployment checklist

  • Ubuntu updated
  • Git + Node installed
  • Repo cloned
  • .env created
  • npm install + build done
  • PM2 running and saved (pm2 startup + pm2 save)
  • Nginx installed and reverse proxy configured
  • Firewall allows SSH + 80/443
  • Backend reachable
  • Domain + SSL (recommended next step)

Final URLs

  • Without Nginx: http://SERVER_IP:5000
  • With Nginx: http://SERVER_IP
  • With SSL: https://yourdomain.com

Once PM2 and Nginx are stable, every deploy is usually: git pull → build → pm2 restart backend.

#aws#ec2#nodejs#nginx#pm2#devops
Share:

Comments

0

Login to post a comment.

Sign in

Loading comments…