View Plans

Node.js Hosting with PM2 & Nginx Reverse Proxy — 2025 Guide

Run production‑ready Node.js apps with PM2 as a process manager and Nginx as a reverse proxy. This guide covers cluster mode, ecosystem.config.js, HTTPS via Let's Encrypt, graceful reloads, rolling restarts, logging, and everyday tuning.

FTP uploads and ad‑hoc scripts make apps fragile. A tidy PM2 + Nginx setup gives you predictable behavior, structured logs, and safe updates while keeping resource usage efficient.

Table of Contents

  1. Prerequisites
  2. Install Node.js (LTS) and PM2
  3. Create ecosystem.config.js
  4. Configure Nginx reverse proxy
  5. Add HTTPS with Let's Encrypt
  6. Logs & logrotate
  7. Graceful reloads & rolling restarts
  8. Scale with PM2 cluster mode
  9. FAQs

1) Prerequisites

  • SSH access to your hosting account or server
  • Node.js LTS (v18+ recommended) and Git installed
  • Domain pointed to the server (A/AAAA records)

2) Install Node.js (LTS) and PM2

curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs build-essential
sudo npm i -g pm2
pm2 startup # prints a system command — run it to enable auto‑start

3) Create ecosystem.config.js

module.exports = {
  apps: [{
    name: "my-app",
    script: "server.js",
    instances: "max",
    exec_mode: "cluster",
    env: { NODE_ENV: "production", PORT: 3000 },
    max_memory_restart: "512M",
    out_file: "~/logs/my-app.out.log",
    error_file: "~/logs/my-app.err.log",
    merge_logs: true,
    watch: false
  }]
}
# start & save
pm2 start ecosystem.config.js && pm2 save

4) Configure Nginx reverse proxy

# /etc/nginx/sites-available/my-app.conf
server {
  listen 80;
  server_name example.com www.example.com;

  location / {
    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_pass http://127.0.0.1:3000;
    proxy_read_timeout 60s;
  }

  # static assets (optional micro cache)
  location ~* \.(css|js|svg|ico|png|jpg|jpeg|webp)$ {
    expires 7d;
    add_header Cache-Control "public";
    try_files $uri @app;
  }
  location @app { proxy_pass http://127.0.0.1:3000; }
}
# enable and test
sudo ln -s /etc/nginx/sites-available/my-app.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

5) Add HTTPS with Let's Encrypt

sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
# auto‑renew
sudo systemctl enable certbot.timer && sudo systemctl start certbot.timer

6) Logs & logrotate

  • Use pm2 logs my-app for live tails
  • Rotate with logrotate (daily or size‑based) to avoid disk bloat
  • Ship structured logs to an external store if needed

7) Graceful reloads & rolling restarts

# apply code changes without dropping connections
pm2 reload my-app
# restart one instance at a time for stability
pm2 restart my-app --update-env

8) Scale with PM2 cluster mode

  • Use instances: "max" to span CPU cores
  • For WebSocket/session apps, consider sticky sessions at the proxy
  • Watch CPU/RAM and right‑size your plan before adding more features
Launch a robust Node.js stack
Run PM2 in cluster mode behind Nginx with automatic HTTPS and clean logs.

9) FAQs

Do I need root access?

Full root is convenient, but many hosts support PM2 and Nginx on managed plans. Check what your plan allows.

Can I use Apache instead of Nginx?

Yes. Use ProxyPass/ProxyPassReverse with similar headers. Nginx is popular for its lean footprint.

How do I set environment variables?

Define them in ecosystem.config.js (env: {}) or your shell profile; avoid committing secrets to Git.