pm2 icon indicating copy to clipboard operation
pm2 copied to clipboard

startup script: SELinux prevents PM2 from starting up on CentOS 8

Open debel27 opened this issue 4 years ago • 8 comments

What's going wrong?

On CentOS 8, pm2 startup generates a systemd service that is incompatible with the default security policy enforced by SELinux. Because of that, the service won't start.

How could we reproduce this issue?

On CentOS 8, just run pm2 startup. After following the instructions, start the service. It won't be able to start.

Supporting information

I've opened a StackExchange issue that explains the problem. I think the issue is that the PIDFile property of the service is a path to the home directory :

PIDFile=/home/john/.pm2/pm2.pid

I think this drifts away from the convention of having PID files in the /run directory, and this is probably why I get this error when I start the service

SELinux is preventing systemd from read access on the file pm2.pid.

To me, the reason is due to the mismatch between these two contexts

Source Context                system_u:system_r:init_t:s0
Target Context                system_u:object_r:user_home_t:s0

I believe the problem would be solved by having the PID file generated in the /run directory (actually I checked, and it worked).

debel27 avatar Aug 15 '20 19:08 debel27

I personally gave up on pm2 startup because of this issue, and that pm2 startup doesn't write PM2_* variables into the environment of the service file it generates. PID file and log file path should be flags for pm2 startup, or at a bare minimum, transcribe PM2_PID_FILE_PATH and PM2_LOG_FILE_PATH into the service file generated. It should default to what the system expects, however, instead of what it is currently doing.

I get that pm2 wanted to be tidy and keep everything in one place, but violating system conventions asks for trouble. PIDs of systemd registered services are typically supposed to go in to /var/run, logs in /var/log. pm2 startup should respect system conventions and default to what the system expects. Otherwise you run up against other system built in features like SELinux which expect conventions to be followed, and cause great misery for your users.

I am working around this issue with ansible to create the service myself, but it's a headache I have to maintain now.

Have two big thumbs up fellow sufferer.

👍 👍

xiata avatar Aug 17 '20 19:08 xiata

I could solve my issue by lifting restrictions, but as you said it would be way better if PM2 followed system conventions in the first place. I'm setting up an execution environment and PM2 is the only thing that doesn't go smoothly.

debel27 avatar Aug 17 '20 22:08 debel27

Related issue #4776

epexa avatar Nov 21 '20 05:11 epexa

Allowing the user to specify the location of the PID file would be a potential workaround. However, if you edit the generated unit file for systemd, specifying an alternate location for PIDFile, PM2 still writes the file at PM2_HOME/pm2.pid. The SELinux error goes away, but systemd is unaware that PM2 has successfully started and will continually try to start it until this file exists. Manually copying the file from PM2_HOME to the more sensible location (/var/run) makes everything happy until the next reboot.

collinjc avatar Feb 19 '21 00:02 collinjc

The issue, as I see it, is that, regardless of the value chosen for PIDFile, PM2 ignores it. From what I can tell, paths.js has this hardcoded to PM2_HOME/pm2.pid. If this was changed so that it could be decoupled from PM2_HOME, at least there would be an acceptable workaround.

collinjc avatar Feb 26 '21 23:02 collinjc

In the absence of a real solution to this problem, the following is the workaround that I've devised. It's far from elegant, but it'll get the job done until this is properly addressed. In the systemd service file for pm2, change the value for PIDFile as follows: PIDFile=/run/pm2.pid Because pm2 ignores this and writes the PID file to PM2_HOME anyway, we will also need the following: ExecStartPre=/usr/bin/rm -f /run/pm2.pid ExecStartPost=/usr/bin/cp /root/.pm2/pm2.pid /run/pm2.pid

Be sure that ExecStartPost references the correct location of PM2_HOME for your installation.

collinjc avatar Mar 09 '21 18:03 collinjc

This method is the best at the moment:

Edit file: /etc/systemd/system/pm2-root.service

  1. Add new line: Environment=PM2_PID_FILE_PATH=/run/pm2.pid

  2. And replace: PIDFile=/root/.pm2/pm2.pid to: PIDFile=/run/pm2.pid

Versions:

  • CentOS 8.3.2011
  • Node.js 14.16.0
  • NPM 7.7.5
  • PM2 4.5.5

Original answer. Thanks Alec!

epexa avatar Mar 30 '21 01:03 epexa

Just wanted to mention that only root can write in /run. If you want to run it as a non-root user, you need to add the entry RuntimeDirectory=pm2 and Environment=PM2_PID_FILE_PATH=/run/pm2/pm2.pid. Then replace the entry for PIDFile with /run/pm2/pm2.pid.

johnkmzhou avatar May 08 '24 22:05 johnkmzhou