Running PM2 5.3.1 as a non-root started service by systemd

NodeJS... So there are various process managers available that are developed specifically to provide high availability for NodeJS (or NextJS for that matter) applications. One of those process managers is PM2.

Running PM2 as a non-root user is not so easy though and requires several manual steps in addition to what PM2 itself provides.

Edit the systemd unit file created as /etc/systemd/system/pm2-pm2.service (thus assuming the user pm2 that should be running pm2 here).

It should currently contain something like below.

[Unit]
Description=PM2 process manager
Documentation=https://pm2.keymetrics.io/
After=network.target

[Service]
Type=forking
User=pm2
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Environment=PATH=/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
Environment=PM2_HOME=/home/pm2/.pm2
PIDFile=/home/pm2/.pm2/pm2.pid
Restart=on-failure

ExecStart=/usr/local/lib/node_modules/pm2/bin/pm2 resurrect
ExecReload=/usr/local/lib/node_modules/pm2/bin/pm2 reload all
ExecStop=/usr/local/lib/node_modules/pm2/bin/pm2 kill

[Install]
WantedBy=multi-user.target

You can see several things here you might want to have changed, such as the pid location; which preferably lives in /run/pm2 or something alike. Make sure to create that directory beforehand and chown it to pm2:pm2.

Now put the definition below in the unit file.

[Unit]
Description=PM2 process manager
Documentation=https://pm2.keymetrics.io/
After=network.target

[Service]
User=pm2
Group=pm2
Type=forking
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Environment=PATH=/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
Environment=PM2_HOME=/home/pm2/.pm2
Environment=PM2_PID_FILE_PATH=/run/pm2/pm2.pid
PIDFile=/run/pm2/pm2.pid
Restart=on-failure
RuntimeDirectory=pm2

ExecStartPre=/usr/bin/rm -f /run/pm2/pm2.pid
ExecStart=/usr/local/lib/node_modules/pm2/bin/pm2 resurrect -u pm2
ExecReload=/usr/local/lib/node_modules/pm2/bin/pm2 reload all -u pm2
ExecStop=/usr/local/lib/node_modules/pm2/bin/pm2 kill -u pm2

[Install]
WantedBy=multi-user.target

Note the "Group", "Environment", "PIDFile" and most importantly "RuntimeDirectory" and "ExecStartPre". The latter two actually prevent vague SELinux related errors that tell you the pid file can't be accessed.

Don't forget to run systemctl daemon-reload.

Notes

Note that you might have to remove /home/pm2/.pm2/pub.sock and /home/pm2/.pm2/rpc.sock in case you started pm2 before starting it as service using systemctl start pm2-pm2.service as the (SELinux) permissions might not be correct (anymore).

Job for pm2-pm2.service failed because the service did not take the steps required by its unit configuration.
See "systemctl status pm2-pm2.service" and "journalctl -xeu pm2-pm2.service" for details.
pm2-pm2.service: Can't open PID file /run/pm2/pm2.pid (yet?) after start: Operation not permitted.
type=AVC msg=audit(1709583009.187:56072): avc:  denied  { read } for  pid=1 comm="systemd" name="pm2.pid" dev="vda1" ino=247475917 scontext=system_u:system_r:init_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=0