Node.js Hosting: Options, PM2 & Server Setup


Our Node.js server support team runs production Node.js apps on VPS, containers, and PaaS platforms. This page documents the options and the standard self-managed setup: hosting models with their cost and control trade-offs, Node version selection, server preparation, PM2 process management, an nginx reverse proxy, SSL, deployment, and the failures that account for most incidents.
Hosting options
| Option | What it is | Trade-off |
|---|---|---|
| VPS / dedicated (self-managed) | A Linux server you administer: Node installed directly, a process manager keeps the app alive, nginx in front. The rest of this page describes this setup. | Lowest cost per unit of compute and full control; you own OS patching, process management, TLS, and monitoring. |
| Containers | The app packaged as a Docker image, run on a container host or an orchestrator (Kubernetes, ECS, Cloud Run). The image pins the Node version and dependencies. | Reproducible builds and easy horizontal scaling; adds an image pipeline and orchestration layer to operate. |
| PaaS (Render, Railway, Heroku-class) | Push code or connect a repo; the platform builds, runs, restarts, and terminates TLS. Render and Railway deploy from Git with per-service pricing; Heroku popularized the dyno model. | No server administration at all; highest cost per unit of compute, and platform limits (build time, egress, background workers) apply. |
| Serverless functions | Individual handlers (AWS Lambda, Cloudflare Workers, Vercel Functions) invoked per request, billed per execution. | No idle cost and automatic scaling; cold starts, execution time limits, and no long-lived processes — WebSockets and persistent connections need different handling. |
The self-managed VPS model is the default for apps with steady traffic: a $10–40/month server runs workloads that cost several times that on a PaaS. PaaS is the right answer when nobody on the team will maintain a server.
Which Node version to install
Install the Active LTS release unless a dependency requires otherwise. Per the Node.js release schedule, even-numbered major versions become LTS; odd-numbered versions are short-lived development releases and do not belong on production servers. As of August 2026, Node 24 (Krypton) is Active LTS, Node 22 (Jod) is in Maintenance LTS, and Node 26 is the Current release. Node 20 reached end of life in March 2026 — servers still on it should be upgraded.
Server setup
Two standard install paths. NodeSource provides distribution packages via its setup scripts (system-wide, one version); nvm installs per-user and switches versions easily. NodeSource on Ubuntu/Debian:
curl -fsSL https://deb.nodesource.com/setup_24.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo apt-get install -y nodejs
node -v
Run the app as a dedicated non-root user. Node processes do not need root; a compromise of the app then stays inside that account:
sudo adduser --system --group nodeapp
sudo mkdir -p /var/www/myapp
sudo chown nodeapp:nodeapp /var/www/myapp
Deploy the code into that directory, run npm ci (not npm install — ci installs exactly what the lockfile specifies), and confirm the app starts by hand before adding a process manager.
PM2 process management
A Node process that crashes stays down until something restarts it. PM2 is the standard process manager: it restarts the app on crash, starts it on boot, and runs multiple instances behind Node's cluster module.
sudo npm install pm2@latest -g
pm2 start app.js --name myapp
pm2 save
pm2 startup
pm2 save writes the current process list to disk; pm2 startup prints a command that registers a systemd unit so the saved list resurrects after a reboot. Run both — a PM2 setup without them survives crashes but not reboots.
Cluster mode runs one worker per CPU core behind a shared port, which is how a single Node process uses a multi-core server:
pm2 start app.js --name myapp -i max
Day-to-day commands: pm2 list shows process status and restart counts, pm2 logs myapp tails stdout and stderr, pm2 restart myapp hard-restarts, and pm2 reload myapp restarts workers one at a time for zero-downtime deploys (cluster mode only). Crash restarts are automatic; a process that restarts too fast too often is put into an errored state rather than looping forever.
nginx reverse proxy
Do not expose Node directly on port 80/443. nginx in front terminates TLS, serves static files, and buffers slow clients. The canonical proxy block, including the headers WebSocket upgrades require:
server {
listen 80;
server_name example.com;
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;
}
}
The Upgrade and Connection headers are what make WebSockets work through the proxy; omitting them is the most common cause of Socket.IO connections silently falling back to polling. Bind the Node app to 127.0.0.1, not 0.0.0.0, so it is reachable only through nginx.
SSL
One command: Let's Encrypt via sudo certbot --nginx -d example.com obtains the certificate, rewrites the nginx config for HTTPS, and installs the renewal timer.
Environment and configuration
Configuration goes in environment variables, read from a .env file loaded at startup (Node 24 reads it natively with the --env-file flag; the dotenv package does the same on older versions). The .env file stays on the server and in .gitignore. Secrets committed to a repository are compromised the moment the repository is cloned anywhere; rotating them after the fact is the cleanup, not the fix. PM2 picks up environment changes on pm2 restart myapp --update-env.
Deployment patterns
- Manual:
git pull,npm ci,pm2 reload myapp. Adequate for one server and one deployer. - CI-driven: the same three steps executed by a pipeline (GitHub Actions over SSH is the common shape) on push to the main branch. Removes the "worked on my machine" deploys.
- Zero-downtime:
pm2 reloadin cluster mode cycles workers one at a time, so requests are never dropped during a deploy. A hardpm2 restartdrops in-flight requests; use it only when the reload path is unavailable.
Monitoring basics
pm2 monit shows live CPU and memory per process; pm2 list exposes the restart counter, which is the first thing to check when an app misbehaves — a climbing restart count means the app is crashing and PM2 is masking it. Add a health endpoint (/healthz returning 200 and a DB ping) and point an external uptime check at it; PM2 knows the process is up, not that the app is answering correctly.
Common failures
- EADDRINUSE (port in use): a previous instance did not exit, or the app was started both by PM2 and by hand. Find it with
lsof -i :3000; never run the app outside PM2 on the same port. - EMFILE (too many open files): the process hit the file-descriptor limit — either raise
ulimit -nvia systemd/PM2 limits, or fix the leak (unclosed sockets, streams, or watchers). - Memory-leak restart loops: heap grows until the process dies or
--max-old-space-sizeis hit; PM2 restarts it and the cycle repeats. The restart counter climbs steadily. Capture a heap snapshot and find the retained objects;pm2 start app.js --max-memory-restart 500Mis a containment measure, not a fix. - Crash loops on boot: the app throws during startup (missing env var, unreachable DB), PM2 retries, and the errored state appears in
pm2 list. The cause is always inpm2 logs— read them before restarting again.
When to hand it over
Everything above is standard work, and it is also permanent work: OS patching, Node upgrades on the LTS schedule, certificate issues, restart-loop diagnosis at whatever hour they happen. Our application server support service covers Node.js hosting end to end — setup, PM2 and nginx configuration, deployment pipelines, and 24/7 incident response — alongside the other stacks described in application servers.
Topics

Sreenivasa Reddy G
Founder & CEO • 15+ years
Sreenivasa Reddy is the Founder and CEO of Medha Cloud, recognized as "Startup of the Year 2024" by The CEO Magazine. With over 15 years of experience in cloud infrastructure and IT services, he leads the company's vision to deliver enterprise-grade cloud solutions to businesses worldwide.
More in Hosting Solutions
View all
Apache vs Tomcat: Differences & When to Use Each
9 min read

Apache Tomcat: Download, Setup & Versions
10 min read

IIS SSL Certificate: Install, Bind & Renew
9 min read

MySQL Support: Oracle Tiers, Contacts & Options
8 min read

MySQL Performance Tuning: Slow Queries, InnoDB & Config
10 min read

MySQL vs MariaDB: Differences, Compatibility & Licensing
10 min read