DEV Community

Mushood
Mushood

Posted on

How to Deploy a Node.js Backend the Correct Way with Nginx + PM2 on Any VPS

 # Deploying a Node.js Backend in Production with PM2 & Nginx

Deploying a Node.js backend is easy until you do it on a real VPS server.

Locally, everything works perfectly:

npm start
Enter fullscreen mode Exit fullscreen mode

The API launches, connects to the database, Postman returns the correct response, and everything looks good.

But once you move your project to a production server, you'll quickly face questions like:

  • What happens if the server reboots?
  • Will the application restart automatically?
  • Should users access port 5000 directly?
  • How do you configure HTTPS?
  • Where do logs go?
  • How should you restart the application after deployment?

These are common mistakes during a first production deployment.

Many beginners simply run:

node server.js
Enter fullscreen mode Exit fullscreen mode

While this works for testing, it is not suitable for production.

Problems with this approach:

  • The process may stop when your SSH session ends.
  • If the app crashes, it won't restart automatically.
  • After a server reboot, your application stays offline.

Instead, a proper production setup uses:

  • PM2 — Process manager for Node.js
  • Nginx — Reverse proxy and web server

Production Architecture

Internet
   │
   ▼
Nginx (80 / 443)
   │
   ▼
Node.js App (localhost:5000)
   │
   ▼
PM2 Process Manager
Enter fullscreen mode Exit fullscreen mode

Important: Users should never communicate directly with your Node.js application.

Instead of exposing:

http://your-server-ip:5000
Enter fullscreen mode Exit fullscreen mode

Users should access:

https://your-domain.com
Enter fullscreen mode Exit fullscreen mode

Nginx receives the request, handles HTTP/HTTPS, and forwards it to your backend.


Step 1 — Connect to Your Server

If using the root user:

ssh root@your-server-ip
Enter fullscreen mode Exit fullscreen mode

Or if using Ubuntu:

ssh ubuntu@your-server-ip
Enter fullscreen mode Exit fullscreen mode

Replace your-server-ip with your VPS IP address.


Step 2 — Update Your Server

Always update the package list first.

sudo apt update && sudo apt upgrade -y
Enter fullscreen mode Exit fullscreen mode

Step 3 — Install Node.js

For Node.js v20:

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install nodejs -y
Enter fullscreen mode Exit fullscreen mode

Verify the installation:

node -v
npm -v
Enter fullscreen mode Exit fullscreen mode

Step 4 — Clone Your Backend Project

Clone your repository:

git clone https://github.com/your-username/your-backend-repo.git
Enter fullscreen mode Exit fullscreen mode

Move into the project:

cd your-backend-repo
Enter fullscreen mode Exit fullscreen mode

Install dependencies:

npm install
Enter fullscreen mode Exit fullscreen mode

If your application uses environment variables:

nano .env
Enter fullscreen mode Exit fullscreen mode

Example:

PORT=5000
DATABASE_URL=your_database_url
JWT_SECRET=your_secret_key
NODE_ENV=production
Enter fullscreen mode Exit fullscreen mode

Never commit your .env file.

.gitignore

.env
Enter fullscreen mode Exit fullscreen mode

Step 5 — Test the Application

If you have a start script:

npm start
Enter fullscreen mode Exit fullscreen mode

Otherwise:

node server.js
Enter fullscreen mode Exit fullscreen mode

This verifies that:

  • Environment variables are correct
  • Database connection works
  • Dependencies are installed
  • Production configuration is valid

Stop the application afterward:

CTRL + C
Enter fullscreen mode Exit fullscreen mode

Step 6 — Install PM2

Install PM2 globally:

sudo npm install pm2 -g
Enter fullscreen mode Exit fullscreen mode

Start your application.

Using server.js:

pm2 start server.js --name backend-api
Enter fullscreen mode Exit fullscreen mode

Or using the npm start script:

pm2 start npm --name backend-api -- start
Enter fullscreen mode Exit fullscreen mode

Verify:

pm2 list
Enter fullscreen mode Exit fullscreen mode

Step 7 — Enable Auto Startup

Generate the startup script:

pm2 startup
Enter fullscreen mode Exit fullscreen mode

PM2 will display another command.

Run the generated command (it begins with sudo).

Finally save the process list:

pm2 save
Enter fullscreen mode Exit fullscreen mode

Now your application starts automatically after server reboots.


Step 8 — Install Nginx

Install Nginx:

sudo apt install nginx -y
Enter fullscreen mode Exit fullscreen mode

Start the service:

sudo systemctl start nginx
Enter fullscreen mode Exit fullscreen mode

Enable startup:

sudo systemctl enable nginx
Enter fullscreen mode Exit fullscreen mode

Check status:

sudo systemctl status nginx
Enter fullscreen mode Exit fullscreen mode

Step 9 — Configure Nginx

Create a configuration file:

sudo nano /etc/nginx/sites-available/backend
Enter fullscreen mode Exit fullscreen mode

Paste the following:

server {
    listen 80;

    server_name your-domain.com www.your-domain.com;

    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;
    }
}
Enter fullscreen mode Exit fullscreen mode

Replace your-domain.com with your real domain.

Enable the configuration:

sudo ln -s /etc/nginx/sites-available/backend /etc/nginx/sites-enabled/
Enter fullscreen mode Exit fullscreen mode

Test the configuration:

sudo nginx -t
Enter fullscreen mode Exit fullscreen mode

Restart Nginx:

sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

Step 10 — Configure the Firewall

If you're using UFW:

Allow SSH:

sudo ufw allow OpenSSH
Enter fullscreen mode Exit fullscreen mode

Allow HTTP & HTTPS:

sudo ufw allow 'Nginx Full'
Enter fullscreen mode Exit fullscreen mode

Enable the firewall:

sudo ufw enable
Enter fullscreen mode Exit fullscreen mode

Only these ports should be accessible:

  • SSH
  • HTTP (80)
  • HTTPS (443)

Do not expose port 5000.


Step 11 — Configure HTTPS with Certbot

Install Certbot:

sudo apt install certbot python3-certbot-nginx -y
Enter fullscreen mode Exit fullscreen mode

Generate the SSL certificate:

sudo certbot --nginx -d your-domain.com -d www.your-domain.com
Enter fullscreen mode Exit fullscreen mode

Certbot automatically:

  • Creates SSL certificates
  • Updates your Nginx configuration
  • Redirects HTTP → HTTPS

Useful PM2 Commands

Check running applications

pm2 list
Enter fullscreen mode Exit fullscreen mode

Restart application

pm2 restart backend-api
Enter fullscreen mode Exit fullscreen mode

Stop application

pm2 stop backend-api
Enter fullscreen mode Exit fullscreen mode

Delete application

pm2 delete backend-api
Enter fullscreen mode Exit fullscreen mode

View logs

pm2 logs
Enter fullscreen mode Exit fullscreen mode

Open monitoring dashboard

pm2 monit
Enter fullscreen mode Exit fullscreen mode

Save current process list

pm2 save
Enter fullscreen mode Exit fullscreen mode

The most useful command during debugging:

pm2 logs
Enter fullscreen mode Exit fullscreen mode

Typical Deployment Workflow

Once everything is configured, future deployments become simple.

cd your-backend-repo

git pull

npm install

pm2 restart backend-api
Enter fullscreen mode Exit fullscreen mode

Why Use PM2 & Nginx?

Instead of exposing your Node.js server directly, using PM2 and Nginx provides several advantages:

  • Automatic application restarts
  • Auto-start after server reboot
  • SSL/TLS support
  • Reverse proxy functionality
  • Better logging
  • Easier scaling
  • Multiple applications or subdomains on one server
  • Improved security

Production Best Practices

Use environment variables

Good:

process.env.JWT_SECRET
Enter fullscreen mode Exit fullscreen mode

Bad:

const jwtSecret = "your_secret_here";
Enter fullscreen mode Exit fullscreen mode

Only expose necessary ports

Open only:

  • 22 (SSH)
  • 80 (HTTP)
  • 443 (HTTPS)

Avoid exposing your application port (5000).


Always monitor logs

pm2 logs
Enter fullscreen mode Exit fullscreen mode

Restart after deployment

pm2 restart backend-api
Enter fullscreen mode Exit fullscreen mode

Summary

Production deployment is much more than simply starting your Node.js application.

A production-ready backend should:

  • ✅ Automatically restart after crashes
  • ✅ Start after server reboots
  • ✅ Use HTTPS
  • ✅ Hide internal application ports
  • ✅ Generate accessible logs
  • ✅ Be easy to update and maintain

Using PM2 together with Nginx provides a reliable, secure, and scalable setup for deploying Node.js applications on any Ubuntu-based VPS, whether it's AWS EC2, DigitalOcean, Hetzner, Azure, Linode, Contabo, or similar cloud providers.

Top comments (0)