Developer Stacks

How to Deploy Next.js 14 & 15 App on Ubuntu VPS with PM2 and Nginx (Full SSR Guide)

How to Deploy Next.js 14 & 15 App on Ubuntu VPS with PM2 and Nginx (Full SSR Guide) - CpanelFree Guide
Written by Blog

Why Self-Host Next.js on a Linux Cloud VPS?

Next.js has become the most popular React framework for modern full-stack web development, offering Server-Side Rendering (SSR), React Server Components (RSC), incremental static regeneration (ISR), and API route handlers. While managed hosting platforms like Vercel or Netlify offer simple git deployments, their bandwidth and serverless function execution costs escalate dramatically once your application receives millions of pageviews.

Self-hosting Next.js on an affordable, high-performance Ubuntu Cloud VPS gives you total control over CPU resources, unmetered bandwidth, local caching engines (such as Redis), custom persistent file storage, and persistent database connections—all at a fixed, predictable hosting cost.

In this production-grade tutorial, we will configure Next.js 14/15 on Ubuntu 24.04/22.04 LTS using standalone build optimizations, PM2 process management in cluster mode, and an Nginx reverse proxy configured with HTTP/2 and Let’s Encrypt SSL.

Step 1: Installing Node.js 20 LTS and Essential Build Tools

Next.js 14 and 15 recommend Node.js 18.17+ or Node.js 20 LTS. We install Node.js 20 LTS using the official NodeSource APT repository along with build essentials:

# Update APT metadata and install prerequisite packages
sudo apt update && sudo apt install -y curl git build-essential nginx certbot python3-certbot-nginx

# Add NodeSource Node.js 20 LTS repository
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

# Verify Node.js and NPM versions
node -v
npm -v

# Install PM2 globally
sudo npm install -g pm2

Step 2: Configuring Next.js Standalone Output Mode

By default, Next.js packages all development dependencies, which can result in a deployment folder larger than 1GB. Enabling output: 'standalone' tells Next.js to leverage tree-shaking and bundle only the exact production files needed to run the server, reducing memory footprint by up to 80%.

In your Next.js project root, edit next.config.mjs (or next.config.js):

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone',
  reactStrictMode: true,
  poweredByHeader: false,
  compress: true,
  images: {
    domains: ['cpanelfree.com'],
    formats: ['image/avif', 'image/webp'],
  },
};

export default nextConfig;

Step 3: Cloning, Installing, and Building on VPS

Clone your Next.js repository into /var/www/next-app and build the production bundle:

# Create webroot and clone repository
sudo mkdir -p /var/www/next-app
sudo chown -R $USER:$USER /var/www/next-app
git clone https://github.com/your-username/your-next-repo.git /var/www/next-app

cd /var/www/next-app

# Install dependencies and build
npm ci
npm run build

# Copy static assets and public folder into standalone directory
cp -r public .next/standalone/
cp -r .next/static .next/standalone/.next/

Step 4: Managing Next.js with PM2 Cluster Mode

To ensure high availability and automatic restarts upon crashes or server reboots, create a PM2 configuration file ecosystem.config.cjs in your project directory:

module.exports = {
  apps: [
    {
      name: 'nextjs-production',
      cwd: '/var/www/next-app/.next/standalone',
      script: 'server.js',
      instances: 'max',
      exec_mode: 'cluster',
      env: {
        NODE_ENV: 'production',
        PORT: 3000,
        HOSTNAME: '127.0.0.1',
      },
      max_memory_restart: '600M',
      error_file: '/var/log/nextjs-error.log',
      out_file: '/var/log/nextjs-out.log',
    },
  ],
};

Launch the PM2 process and save the systemd auto-start configuration:

# Start Next.js with PM2
pm2 start ecosystem.config.cjs

# Save PM2 process list and configure auto-start on server boot
pm2 save
pm2 startup systemd

Step 5: Nginx Reverse Proxy with WebSocket & Caching Directives

Create an optimized Nginx server block at /etc/nginx/sites-available/next.example.com:

server {
    listen 80;
    server_name next.example.com;

    # Gzip compression for high-speed delivery
    gzip on;
    gzip_proxied any;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;

    location /_next/static/ {
        alias /var/www/next-app/.next/static/;
        expires 365d;
        access_log off;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }

    location / {
        proxy_pass http://127.0.0.1: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;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 60s;
    }
}

Enable the site configuration and acquire an SSL certificate:

sudo ln -s /etc/nginx/sites-available/next.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d next.example.com

Next.js VPS Deployment Architecture Matrix

Architecture Layer Technology Role & Responsibility Performance Impact
Edge Gateway Nginx Reverse Proxy SSL Termination & Static Assets Cache Sub-5ms static asset delivery
Process Supervisor PM2 Cluster Multi-core load balancing & self-healing 100% uptime with zero downtime reloads
Application Engine Next.js Standalone Server-Side Rendering & React Server Components 80% reduced memory footprint

Frequently Asked Questions (FAQ)

How do I update the Next.js app with zero downtime?

To deploy new updates without interrupting live visitor sessions, pull the latest code, run npm run build, copy the updated static files, and execute pm2 reload nextjs-production. PM2 will reload each cluster worker sequentially.

Can I connect Next.js to a local PostgreSQL database?

Yes. You can install PostgreSQL directly on the same Ubuntu VPS and connect using Prisma ORM or Drizzle via postgresql://user:[email protected]:5432/dbname for ultra-low 0.1ms internal database latency.

Automating Continuous Zero-Downtime Deployments with GitHub Actions

To eliminate manual SSH logins and ensure that every merged pull request triggers an automated build, validation, and zero-downtime cluster reload, configure a GitHub Actions deployment workflow at .github/workflows/deploy.yml:

name: Next.js Zero-Downtime Deployment

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
      - run: npm ci
      - run: npm run build
      - name: Deploy to Cloud VPS via SSH
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /var/www/next-app
            git pull origin main
            npm ci
            npm run build
            cp -r public .next/standalone/
            cp -r .next/static .next/standalone/.next/
            pm2 reload nextjs-production
            echo "Next.js cluster reloaded with zero downtime!"

Next.js VPS Troubleshooting & Common Pitfalls

Symptom Cause Resolution
Missing static CSS/JS (404 on /_next/static/) Static folder not copied to standalone directory Run cp -r .next/static .next/standalone/.next/
High memory consumption / OOM crash PM2 cluster running too many workers on small VPS Set instances: 2 and configure a 2GB swapfile
Image optimization failing (500 error) Missing sharp image library in standalone mode Run npm install sharp in project root

Deploy Full-Stack Next.js Apps on CpanelFree High-Speed VPS

Scale your React and SSR web applications with high-speed NVMe cloud servers, unmetered bandwidth, and 100% free hosting options.

Launch Free Cloud Hosting →

Deploy Fast, Reliable Web Hosting on CpanelFree

Get genuine cPanel control, unmetered NVMe SSD storage, and free AutoSSL at $0 cost forever.

Claim Free Hosting Account

About the author

Blog

DevOps architect and Linux sysadmin specializing in server hardening, OpenLiteSpeed performance optimization, and free cloud hosting infrastructure.

Leave a Comment