DEV Community

Cover image for Deploy Node.js on Linux with Nginx and PM2 — a practical beginner’s guide
prateekshaweb
prateekshaweb

Posted on • Originally published at prateeksha.com

Deploy Node.js on Linux with Nginx and PM2 — a practical beginner’s guide

Hook: why this stack matters

If you’ve built a Node.js app and want it to run reliably in production, you need more than node app.js and crossed fingers. Using Linux + Nginx + PM2 is a pragmatic stack that gives you stability (Linux), performance and SSL termination (Nginx), and automatic process management with monitoring (PM2). This article walks you through the rationale and a concise, practical path to deploy a real app quickly.

Context: the problem most developers face

New apps fail in production for simple reasons: processes crash, ports are exposed, SSL is missing, or no one set up restarts for server reboots. You need a predictable deployment pattern that:

  • Keeps the app running after crashes and reboots
  • Hides internal ports from the public internet
  • Handles HTTPS, static assets, and load spikes Nginx + PM2 on a Linux VPS solves all of these without heavy orchestration.

Solution overview

The high-level flow looks like this: Nginx listens on 80/443 and proxies to your Node process on an internal port (e.g., 3000). PM2 runs and monitors the Node process, restarts on failure, and can resurrect processes after reboot. Use a PM2 ecosystem file to version your process configuration. These are standard, well-supported tools and work on common distros such as Ubuntu and CentOS.

Quick checklist before you start

  • Provision a Linux server (1–2 GB RAM is fine for small apps).
  • SSH into the server and update packages.
  • Install Node.js (NodeSource or nvm), Nginx, and PM2.
  • Ensure DNS points your domain to the server before issuing SSL.
  • Keep your code and ecosystem config in git.

Implementation: essential steps (short and actionable)

  1. Install Node.js (NodeSource or nvm) and verify node -v and npm -v are correct. If you plan multiple projects or versions, use nvm.
  2. Upload or git-clone your app to a dedicated folder (for example /home/youruser/my-app) and run npm install --production to install dependencies.
  3. Install PM2 globally and start your app with a friendly name: pm2 start app.js --name my-app. Then run pm2 startup and pm2 save so PM2 restarts on reboot.
  4. Install Nginx, create a server block that proxies requests to localhost:3000 (or whatever port your app uses), test nginx -t, and reload Nginx.
  5. Secure the site with Let’s Encrypt (certbot --nginx) to get free HTTPS and automatic renewals.

Notes: don’t expose your Node port to the public internet. Let Nginx handle incoming traffic and SSL.

PM2: make it repeatable

Use an ecosystem.config.js file to describe your app(s) and environment variables. With PM2 you can:

  • Run multiple apps from one file
  • Set NODE_ENV and PORT per environment
  • Use clustering (instances: max) to use all CPU cores Start everything with pm2 start ecosystem.config.js --env production and save the state with pm2 save.

Best practice: avoid watch: true in production. Use CI to trigger restarts instead.

Nginx: reverse proxy basics and tips

Configure Nginx to proxy_pass to http://127.0.0.1:3000 and set common headers like X-Forwarded-For and Host. Keep these in mind:

  • Test Nginx config with nginx -t before reloading.
  • Use gzip and cache headers for static assets.
  • Add basic security headers (X-Frame-Options, X-Content-Type-Options, X-XSS-Protection).

If you host multiple apps, create separate server blocks per domain and point each to its app’s internal port.

Security, monitoring and validation

  • Firewall: enable UFW (Ubuntu) or firewalld (CentOS) and allow SSH and Nginx Full (ports 22, 80, 443).
  • HTTPS: use certbot with the nginx plugin to automate cert issuance and renewal.
  • Logs & monitoring: use pm2 logs and pm2 monit for quick checks. Install pm2-logrotate to avoid log growth.
  • Load test lightly with ab or similar tools and watch pm2 monit, top/htop, and Nginx logs.

Quick best practices:

  • Run Node under a non-root user.
  • Never commit secrets; use environment variables or PM2 env blocks.
  • Regularly run npm audit and keep dependencies updated.

Where to learn more and get help

If you want a ready reference and expanded explanations, check the full guide I used to base this concise workflow on at https://prateeksha.com/blog/deploy-nodejs-on-linux-server-nginx-pm2-beginner-guide. For company and services, see https://prateeksha.com and their blog at https://prateeksha.com/blog.

Conclusion

Deploying Node.js on Linux with Nginx and PM2 gives you a reliable, maintainable base without the complexity of Docker or orchestration. Start small: get Node + PM2 running, put Nginx in front, add HTTPS, and automate with an ecosystem file and CI later. That pattern will cover most production needs for indie projects, MVPs, and early-stage SaaS.

Top comments (0)