📋 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
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
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
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
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
Install Package Manager
Install pnpm globally
npm install -g pnpm
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
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
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
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
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
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
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
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
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 listList all running processes
pm2 restart app_nameRestart specific app
pm2 stop app_nameStop specific app
pm2 delete app_nameDelete app from PM2
pm2 logsView application logs
pm2 monitMonitor processes
Nginx Commands
sudo systemctl status nginxCheck Nginx status
sudo systemctl restart nginxRestart Nginx
sudo nginx -tTest Nginx configuration
sudo systemctl reload nginxReload Nginx config
Troubleshooting
sudo lsof -i :PORTCheck what's using a port
sudo kill -9 $(sudo lsof -t -i:PORT)Kill process on port
pm2 logs app_name --lines 100View recent logs
cat /var/log/nginx/error.logCheck Nginx errors
💡 Pro Tips
- •Always test your Nginx configuration with
sudo nginx -tbefore restarting - •Use
pm2 logsto 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.