Nginx and PM2 Deployment Workflow Complete Guide to Node.js Production Setup
A complete deployment workflow combining Nginx and PM2 for running Node.js applications in production from initial setup to updates and rollback.
Nginx and PM2 Deployment Workflow
This is a complete workflow for deploying a Node.js application using Nginx and PM2 on an EC2 instance.
Initial Setup (One-Time)
1. Install Software
sudo apt update && sudo apt upgrade -y curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - sudo apt install -y nodejs nginx git sudo npm install -g pm2
2. Clone and Configure Project
cd /home/ubuntu git clone https://github.com/yourusername/devtinder-backend.git cd devtinder-backend npm install cp .env.example .env nano .env # Add production values
3. Start with PM2
pm2 start src/server.js --name devtinder-api pm2 save pm2 startup # Follow the instructions outputted
4. Configure Nginx
sudo nano /etc/nginx/sites-available/devtinder
server { listen 80; server_name yourdomain.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_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
sudo ln -s /etc/nginx/sites-available/devtinder /etc/nginx/sites-enabled/ sudo rm /etc/nginx/sites-enabled/default sudo nginx -t sudo systemctl restart nginx
5. Add SSL
sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d yourdomain.com
Regular Deployment (Every Update)
Manual Deployment
# SSH into EC2 ssh -i your-key.pem ubuntu@your-ec2-ip # Pull latest code cd /home/ubuntu/devtinder-backend git pull origin main # Install new dependencies (if any) npm install # Restart PM2 pm2 restart devtinder-api # Verify pm2 status curl http://localhost:3000/api/health
Zero-Downtime Deployment (Reload)
# reload restarts instances one by one (no downtime) pm2 reload devtinder-api
For cluster mode:
pm2 reload devtinder-api
PM2 reloads workers one at a time, keeping the app available throughout.
Automated Deployment Script
Create a deployment script on the server:
nano /home/ubuntu/deploy.sh
#!/bin/bash set -e echo "Starting deployment..." cd /home/ubuntu/devtinder-backend echo "Pulling latest code..." git pull origin main echo "Installing dependencies..." npm install echo "Restarting PM2..." pm2 reload devtinder-api echo "Clearing PM2 logs..." pm2 flush echo "Deployment complete!" pm2 status
chmod +x /home/ubuntu/deploy.sh
Now you can deploy with one command:
./deploy.sh
Rollback Process
If the new deployment has issues:
Option 1: Revert to Previous Commit
cd /home/ubuntu/devtinder-backend # Check recent commits git log --oneline -5 # Revert to previous commit git revert HEAD # Or reset to a specific commit git reset --hard <commit-hash> npm install pm2 reload devtinder-api
Option 2: PM2 Rollback
PM2 doesn't have built-in rollback, but you can keep the previous version:
# Keep two directories /home/ubuntu/devtinder-backend/ # Current /home/ubuntu/devtinder-backend-prev/ # Previous # To rollback: pm2 stop devtinder-api pm2 delete devtinder-api cd /home/ubuntu/devtinder-backend-prev pm2 start src/server.js --name devtinder-api
Health Check After Deployment
# Check if the app is running pm2 status # Check logs for errors pm2 logs devtinder-api --lines 20 # Test the API curl http://localhost:3000/api/health # Test via Nginx (external) curl https://yourdomain.com/api/health # Check Nginx status sudo systemctl status nginx
PM2 Ecosystem File
For complex setups, use an ecosystem file:
nano /home/ubuntu/devtinder-backend/ecosystem.config.js
module.exports = { apps: [{ name: "devtinder-api", script: "src/server.js", instances: "max", // or a specific number exec_mode: "cluster", max_memory_restart: "500M", env: { NODE_ENV: "production", PORT: 3000 }, error_file: "/var/log/devtinder/error.log", out_file: "/var/log/devtinder/out.log", log_date_format: "YYYY-MM-DD HH:mm:ss" }] };
pm2 start ecosystem.config.js pm2 save
The Takeaway
The Nginx + PM2 deployment workflow involves: initial setup (install Node.js, PM2, Nginx, clone project, configure .env, start with PM2, configure Nginx, add SSL), regular deployments (git pull, npm install, pm2 reload for zero downtime), automated deployment scripts, rollback by reverting commits or switching directories, and health checks after deployment. Use ecosystem.config.js for complex setups with cluster mode.
Initial setup: install Node.js, PM2, Nginx, clone project, configure .env, start with PM2, configure Nginx as reverse proxy, add SSL with Let's Encrypt. Regular deployments: git pull, npm install, pm2 reload (zero downtime). Use automated scripts and ecosystem.config.js for complex setups.
Use pm2 reload devtinder-api instead of pm2 restart. In cluster mode, PM2 reloads workers one at a time, keeping the app available throughout. No requests are dropped during the reload.
Option 1: git revert HEAD or git reset --hard <commit-hash>, then npm install and pm2 reload. Option 2: Keep a previous directory (devtinder-backend-prev) and switch PM2 to it: pm2 stop, pm2 delete, cd to prev directory, pm2 start.
A JavaScript file (ecosystem.config.js) that defines app configuration: name, script, instances (max for all cores), exec_mode (cluster), max_memory_restart, environment variables, and log file paths. Start with pm2 start ecosystem.config.js.
Check pm2 status (app is online), pm2 logs --lines 20 (no errors), curl http://localhost:3000/api/health (app responds), curl https://yourdomain.com/api/health (Nginx proxies correctly), and sudo systemctl status nginx (Nginx is running).
Ready to master Node.js completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master Node.js
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

