COMPLETE TUTORIAL

Deploy MERN + Next.js Application on VPS

A step-by-step guide to hosting your full-stack application on a Virtual Private Server with MongoDB, Express, React, Node.js, and Next.js

⏱️ 30 min read🎯 Beginner Friendly📅 Updated Oct 2025

📋 Prerequisites

  • A VPS server (Ubuntu 20.04 or higher recommended)
  • Root or sudo access to your server
  • A domain name (optional but recommended)
  • Your MERN/Next.js project ready on GitHub
  • Basic command line knowledge
🖥️
STEP 1

Initial Server Setup

Connect to your VPS via SSH

ssh root@your_server_ip

Update and upgrade system packages

sudo apt update
sudo apt upgrade
📦
STEP 2

Install Node.js via NVM

Install NVM (Node Version Manager)

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash

Install Node.js LTS version

nvm install --lts

Verify installation

node --version
npm --version
🍃
STEP 3

Install MongoDB

Import MongoDB public GPG key

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

Add MongoDB repository

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

Install MongoDB

sudo apt-get update
sudo apt-get install -y mongodb-org

Start and enable MongoDB

sudo systemctl start mongod
sudo systemctl enable mongod
sudo systemctl status mongod
🔧
STEP 4

Setup Git & Clone Project

Install Git and GitHub CLI

sudo apt install git
sudo apt install gh

Authenticate GitHub CLI

gh auth login

Clone your repository

git clone https://github.com/username/your-project.git
cd your-project
📥
STEP 5

Install Package Manager

Install pnpm globally

npm install -g pnpm
⚙️
STEP 6

Backend Setup

Navigate to backend directory

cd backend

Create environment file

nano .env

Add your environment variables (example)

PORT=5001
MONGO_URI=mongodb://localhost:27017/yourdb
JWT_SECRET=your_secret_key
NODE_ENV=production

Save file (Ctrl+O, Enter, then Ctrl+X)

Install dependencies

pnpm install
🔄
STEP 7

Install & Configure PM2

Install PM2 globally

npm install -g pm2

Start backend with PM2

pm2 start npm --name "backend-app" -- start

Save PM2 configuration

pm2 save
pm2 startup

Test your backend

curl http://localhost:5001
⚛️
STEP 8

Frontend Setup (Next.js)

Navigate to frontend directory

cd ../frontend

Create environment file

nano .env.local

Add your environment variables

NEXT_PUBLIC_API_URL=http://your_server_ip:5001

Install dependencies and build

pnpm install
pnpm run build

Test the build locally

pnpm start
🛡️
STEP 9

Configure Firewall (UFW)

Enable firewall and allow necessary ports

sudo ufw enable
sudo ufw allow 22    # SSH
sudo ufw allow 80    # HTTP
sudo ufw allow 443   # HTTPS
sudo ufw status
🌐
STEP 10

Install & Configure Nginx

Install Nginx

sudo apt install nginx

Navigate to Nginx configuration

cd /etc/nginx/sites-available

Create configuration for Next.js app

sudo nano yourdomain.com.conf

Add this configuration

server {
    listen 80;
    listen [::]:80;
    server_name yourdomain.com www.yourdomain.com;

    client_max_body_size 100M;

    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_cache_bypass $http_upgrade;
    }
}

Create symbolic link and restart Nginx

sudo ln -s /etc/nginx/sites-available/yourdomain.com.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
🔗
STEP 11

Setup Backend API Subdomain

Create API subdomain configuration

cd /etc/nginx/sites-available
sudo nano api.yourdomain.com.conf

Add this configuration

server {
    listen 80;
    listen [::]:80;
    server_name api.yourdomain.com www.api.yourdomain.com;

    client_max_body_size 100M;

    location / {
        proxy_pass http://localhost:5001;
        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;
    }
}

Enable configuration and restart

sudo ln -s /etc/nginx/sites-available/api.yourdomain.com.conf /etc/nginx/sites-enabled/
sudo systemctl restart nginx
🚀
STEP 12

Configure PM2 for Next.js

Create PM2 ecosystem file

cd ~/your-project/frontend
nano ecosystem.config.js

Add this configuration

module.exports = {
  apps: [
    {
      name: "nextjs-app",
      script: "npm",
      args: "start",
      env: {
        PORT: 3000,
        NODE_ENV: "production"
      }
    }
  ]
}

Start application with PM2

pm2 start ecosystem.config.js
pm2 save

Check PM2 status

pm2 status
pm2 logs
🌍
STEP 13

Domain Configuration

Point your domain to your VPS IP in DNS settings:

Type A Record:
Hostname: @
Value: your_server_ip

Type A Record:
Hostname: www
Value: your_server_ip

Type A Record:
Hostname: api
Value: your_server_ip

Update frontend environment to use domain

nano .env.local
# Change to:
NEXT_PUBLIC_API_URL=https://api.yourdomain.com

Rebuild and restart

pnpm run build
pm2 restart nextjs-app
🔒
STEP 14

Install SSL Certificate (Optional)

Install Certbot

sudo apt install certbot python3-certbot-nginx

Obtain SSL certificate

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
sudo certbot --nginx -d api.yourdomain.com

Auto-renewal test

sudo certbot renew --dry-run

🛠️ Useful Commands Reference

PM2 Commands

pm2 list

List all running processes

pm2 restart app_name

Restart specific app

pm2 stop app_name

Stop specific app

pm2 delete app_name

Delete app from PM2

pm2 logs

View application logs

pm2 monit

Monitor processes

Nginx Commands

sudo systemctl status nginx

Check Nginx status

sudo systemctl restart nginx

Restart Nginx

sudo nginx -t

Test Nginx configuration

sudo systemctl reload nginx

Reload Nginx config

Troubleshooting

sudo lsof -i :PORT

Check what's using a port

sudo kill -9 $(sudo lsof -t -i:PORT)

Kill process on port

pm2 logs app_name --lines 100

View recent logs

cat /var/log/nginx/error.log

Check Nginx errors

💡 Pro Tips

  • Always test your Nginx configuration with sudo nginx -t before restarting
  • Use pm2 logs to debug application issues
  • Keep your environment variables secure and never commit them to Git
  • Set up automatic MongoDB backups for production applications
  • Enable UFW firewall to protect your server from unauthorized access

🎉 Congratulations!

You've successfully deployed your MERN + Next.js application on a VPS server. Your application should now be live and accessible via your domain or IP address.