Back to articles
Technology Insight

Deploying Full-Stack Applications (NestJS & React) on Linux VPS with Nginx and PM2

April 14, 2026
Full-Stack NestJS & React Deployment on Linux VPS 2026

Comprehensive Guide: Deploying Full-Stack Applications (NestJS & React) on Linux VPS with Nginx and PM2

Moving an application from a local environment to a production server is a critical milestone in the software development lifecycle. To ensure a stable, self-healing, and secure system, developers must master core Linux tools. This article provides a detailed walkthrough on setting up a Node.js v22 environment, configuring Nginx as a Reverse Proxy, and managing operations with PM2 for NestJS (Backend) and React (Frontend) projects.

1. Environment Preparation: Installing Node.js v22 (LTS)

Node.js v22 introduces significant performance improvements and enhanced ES Modules compatibility. For Ubuntu/Debian installations, using NodeSource is recommended to ensure you receive the latest stable updates.


// Environment version check structure before Deployment
interface EnvSpecs {
    nodeVersion: string;
    requiredVersion: string;
    os: string;
}

function checkEnvironment(specs: EnvSpecs): boolean {
    const current = parseInt(specs.nodeVersion.split('.')[0]);
    const required = parseInt(specs.requiredVersion.split('.')[0]);
    
    if (current < required) {
        console.error(`Error: Node.js ${specs.requiredVersion} required. Current is ${specs.nodeVersion}`);
        return false;
    }
    console.log("Environment valid. Starting build process...");
    return true;
}

const deployEnv: EnvSpecs = { nodeVersion: "22.0.0", requiredVersion: "22.0.0", os: "Ubuntu 24.04" };
checkEnvironment(deployEnv);
    

Run the following commands in your terminal to install:

  • Update system: sudo apt update && sudo apt upgrade -y
  • Install Node.js: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs

2. Process Management with PM2 - Ensuring Zero-Downtime

PM2 is the most powerful process manager for Node.js. It ensures your NestJS application automatically restarts upon a crash and provides centralized log management.


// ecosystem.config.js configuration for a NestJS project
module.exports = {
  apps: [{
    name: "nestjs-backend",
    script: "./dist/main.js",
    instances: "max", // Cluster mode to utilize all CPU cores
    exec_mode: "cluster",
    env: {
      NODE_ENV: "production",
      PORT: 3000
    },
    log_date_format: "YYYY-MM-DD HH:mm Z",
    error_file: "./logs/error.log",
    out_file: "./logs/out.log"
  }]
}
    

Essential PM2 commands to remember:

  • pm2 start ecosystem.config.js: Launch the application according to configuration.
  • pm2 monit: Monitor real-time RAM/CPU consumption of processes.
  • pm2 save: Save the process list to auto-start with the OS.

3. Configuring Nginx as a Reverse Proxy

Nginx acts as the "gatekeeper," receiving HTTP/HTTPS requests from users and routing them to the NestJS application (Backend) or serving static files for React (Frontend).

Feature Frontend (React) Backend (NestJS)
Serving Mechanism Static Files (HTML/JS/CSS) API Proxy (Port 3000)
Nginx Directive root /var/www/react-app/dist; proxy_pass http://localhost:3000;
Optimization Gzip Compression, Browser Caching Rate Limiting, Header Security

// Mock Nginx configuration via TypeScript Interface
interface NginxConfig {
    domain: string;
    backendPort: number;
    sslEnabled: boolean;
    staticPath: string;
}

const webConfig: NginxConfig = {
    domain: "api.example.com",
    backendPort: 3000,
    sslEnabled: true,
    staticPath: "/var/www/frontend/dist"
};

console.log(`Configuring Proxy for domain ${webConfig.domain} to port ${webConfig.backendPort}`);
    

4. Build Workflow and React Frontend Optimization

Unlike the Backend, React must be compiled into client-side code. Vite is commonly used to optimize build speeds.

After running npm run build, the source code will reside in the /dist folder. You must upload this folder to the VPS and point Nginx to it. Ensure try_files is configured to support React Router:


/* Nginx configuration for React Router (Logic Simulation) */
const nginxTryFiles = "try_files $uri $uri/ /index.html";
// This line ensures that when a user refreshes on /dashboard, 
// Nginx returns index.html instead of a 404 error.
    

5. System Security with SSL (Certbot) and Firewall

Modern applications must run on HTTPS. We utilize Let's Encrypt via the Certbot tool for automated SSL management.

  • Install Certbot: sudo apt install certbot python3-certbot-nginx
  • Enable SSL: sudo certbot --nginx -d yourdomain.com
  • Firewall Configuration (UFW): Open only necessary ports like 80, 443, and a custom SSH port.

// Security Header Validation function
function validateSecurityHeaders(headers: Record): boolean {
    const requiredHeaders = ['strict-transport-security', 'x-frame-options', 'content-security-policy'];
    return requiredHeaders.every(h => headers.hasOwnProperty(h));
}

const currentHeaders = {
    'strict-transport-security': 'max-age=31536000',
    'x-content-type-options': 'nosniff'
};
console.log(`Security compliance: ${validateSecurityHeaders(currentHeaders)}`);
    

6. Log Management and System Health Monitoring

When an application runs in Production, logs are your only way to trace errors. Implement Log Rotation to prevent log files from filling up the VPS storage.

PM2 supports pm2-logrotate for automation. Additionally, set up a Cronjob to clean temporary directories periodically.


// Simple Monitoring Configuration Interface
interface HealthCheck {
    serviceName: string;
    uptime: number;
    memoryUsage: number; // MB
    status: 'ALIVE' | 'DEAD';
}

function reportSystemStatus(check: HealthCheck) {
    if (check.memoryUsage > 1024) {
        console.warn(`Warning: Service ${check.serviceName} is consuming excessive RAM!`);
    }
    console.log(`Service: ${check.serviceName} | Uptime: ${check.uptime}s | Status: ${check.status}`);
}

reportSystemStatus({ serviceName: "NestJS-API", uptime: 86400, memoryUsage: 450, status: 'ALIVE' });
    

7. Conclusion: Deployment Success Checklist

To ensure your Full-stack project runs smoothly on a Linux VPS, always go through this checklist before hand-off:

  1. Are environment variables (.env) configured specifically for Production (DB, API Keys)?
  2. Has Nginx been configured with an upload size limit (client_max_body_size)?
  3. Is PM2 set to startup to run automatically after a VPS reboot?
  4. Has the SSL Certificate auto-renewal been verified?
  5. Are database ports (PostgreSQL/MySQL) closed to external access?

Deploying an application is an art of coordinating Code and Infrastructure. Happy building!