Process Managers Compared: PM2 vs systemd vs Supervisor

Every application you deploy needs three things from the server: to keep running, to restart by itself after a crash, and to start again after a reboot. A process manager provides all three. This guide compares the three common choices on a VPS — PM2, systemd and Supervisor — with working configurations for each and a clear recommendation.

Quick Comparison

systemdPM2Supervisor
Installed already?Yes, on every modern distributionNo (npm package)No (apt / dnf package)
LanguagesAnyBuilt for Node.js, runs any commandAny; popular with Python
Starts on bootNativeVia a systemd unit it generatesRuns as a systemd service
Logsjournald (journalctl)Own log files, pm2 logsOwn log files
Resource limits and sandboxingYes — CPU, memory, file-system protectionMemory-based restart onlyNo
Multi-core for Node.jsRun several instancesBuilt-in cluster modeRun several instances

systemd: The Default Choice

systemd is already managing everything else on the server, so your application gets the same tooling: systemctl to control it, journalctl for logs, boot ordering, and resource limits — with nothing extra to install or keep updated.

sudo nano /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network-online.target
Wants=network-online.target

[Service]
User=deploy
WorkingDirectory=/opt/myapp
EnvironmentFile=/opt/myapp/.env
ExecStart=/usr/bin/node /opt/myapp/index.js
Restart=on-failure
RestartSec=3

# limits and sandboxing
MemoryMax=512M
NoNewPrivileges=true
ProtectSystem=full
PrivateTmp=true

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
systemctl status myapp
journalctl -u myapp -f

The same file works for Python (ExecStart=/opt/myapp/venv/bin/gunicorn app:app), Go (the compiled binary) or anything else. More in How to Manage Services with systemd.

PM2: Convenient for Node.js

npm install -g pm2
pm2 start index.js --name myapp -i max     # cluster mode: one process per core
pm2 save
pm2 startup systemd                         # prints a command to run with sudo

PM2’s strengths are the developer-friendly CLI (pm2 ls, pm2 logs, pm2 monit), zero-downtime reloads with pm2 reload myapp, and cluster mode that spreads a Node.js app across all cores without code changes. An ecosystem.config.js file keeps the settings in your repository.

Two things to remember: run pm2 save after changes, or a reboot restores the old process list; and rotate the logs (pm2 install pm2-logrotate), or they grow until the disk is full. Full walkthrough: How to Deploy a Node.js Application with PM2 and Nginx.

Supervisor: Simple INI Files

sudo apt install supervisor -y      # dnf install supervisor on AlmaLinux / Rocky (EPEL)
sudo nano /etc/supervisor/conf.d/myapp.conf
[program:myapp]
command=/opt/myapp/venv/bin/gunicorn myproject.wsgi:application --bind 127.0.0.1:8000
directory=/opt/myapp
user=deploy
autostart=true
autorestart=true
stopasgroup=true
stdout_logfile=/var/log/myapp/out.log
stderr_logfile=/var/log/myapp/err.log
sudo mkdir -p /var/log/myapp
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl status

Supervisor is still common in Python and Django deployments and handles queue workers well (numprocs=4 runs four copies). On a new server, systemd does the same job without the extra service.

Which Should You Use?

  • Most servers: systemd. Nothing to install, works for every language, and gives you limits and sandboxing.
  • Node.js teams who want cluster mode and a friendly CLI: PM2, started by systemd at boot.
  • An existing setup built on Supervisor: keep it; there is no urgent reason to migrate.

Whatever you choose, use one per server — mixing them makes it hard to know what is managing what.

Same Rules for All Three

  • Run applications as an unprivileged user, never as root.
  • Bind the application to 127.0.0.1 and put Nginx in front for HTTPS — see How to Build and Secure a REST API.
  • Keep secrets in an environment file with 600 permissions, not in the unit file or repository.
  • Make sure logs are rotated.

Common Problems

The app runs by hand but fails as a service — usually a missing environment variable or a relative path. Set WorkingDirectory and the environment explicitly, then read journalctl -u myapp -n 50.

Restarts in a loop — systemd stops trying after repeated failures (“start request repeated too quickly”). Fix the crash, then systemctl reset-failed myapp.

PM2 apps gone after reboot — pm2 save was not run, or pm2 startup was run as a different user.

“node: command not found” under systemd — Node installed with NVM lives in the user’s home directory; use its full path in ExecStart (which node as that user).

Continue Reading

Browse more articles in Programming Languages & Runtimes.

  • pm2 vs systemd, process manager, supervisor, application deployment
  • 35 Users Found This Useful
Was this answer helpful?

Related Articles

How to Install PHP on Ubuntu & Debian (Complete Guide)

PHP powers a huge share of the web, including WordPress, Laravel, and Magento. This guide covers...

How to Install Node.js on Ubuntu & Debian (with NVM)

Node.js is a fast JavaScript runtime for building APIs, web applications, and backend services....

How to Install Python on Ubuntu & Debian

Python powers web frameworks like Django and Flask, automation scripts, and data applications....

How to Install Java (OpenJDK) on Ubuntu & Debian

Java powers enterprise applications, build tools like Maven and Gradle, and platforms like...

How to Install Composer for PHP Dependency Management

Composer is PHP's standard dependency manager, used by virtually every modern PHP framework...