问题

CentOS 7中,执行passenger-status报了如下错误:

1
2
3
4
ERROR: Phusion Passenger doesn't seem to be running. If you are sure that it is running, then the causes of this problem could be:
1. You customized the instance registry directory using Apache's PassengerInstanceRegistryDir option, Nginx's passenger_instance_registry_dir option, or Phusion Passenger Standalone's --instance-registry-dir command line argument. If so, please set the environment variable PASSENGER_INSTANCE_REGISTRY_DIR to that directory and run passenger-status again.
2. The instance directory has been removed by an operating system background service. Please set a different instance registry directory using Apache's PassengerInstanceRegistryDir option, Nginx's passenger_instance_registry_dir option, or Phusion Passenger Standalone's --instance-registry-dir command line argument.

而命令passenger-memory-stats可以正常工作。

同样的问题,在Amazon Linux 2 AMI中也同样存在。

机器上Passenger的安装信息如下:

  • 没有通过加载yum源来安装passenger,而是通过gem install passengerpassenger-install-nginx-module来安装的passenger-standalone
  • 安装目录使用的默认路径/opt/nginx/
  • 参照Nginx官方的说明来设置的nginx启动脚本。

原因解析

RHEL 7中systemd的一些安全特性和passenger-status的一些默认值不相匹配,导致了passenger-status命令的不可用。
如下先介绍一下解决过程和其中涉及到的一些知识。

  • systemd PriavteTmp的配置
  • Nginx推荐的nginx.service的写法
  • passenger-status命令中passenger_instance_registry_dir的默认路径

systemd PrivateTmp

先介绍一些RHEL 7 systemd中名为PrivateTmp的配置,这是在RHEL 7中新添加一个新的安全设置,目的是增强系统的安全性。
设立这个设置的原因:

  • 有一些系统服务会使用/tmp目录来保存服务的运行时信息,但/tmp目录默认是任何人都有读写权限的,如果某些系统服务使用/tmp,并依赖于其中的某些配置来运行,那么这些配置有可能被普通用户或者服务所修改,导致安全隐患。
  • 设置PrivateTmp为true,使用systemctl启动服务时,系统会将原来设置到/tmp下的内容分配到/tmp/systemd-private-<random string>-<servicename>.service-<random string>这个的一个命令空间中。并且设置这个目录的权限为700。就可以保证对应的配置文件不会被其他用户和进程所更改。

例如:

1
2
3
4
# ll /tmp/ | grep 'systemd'
drwx------ 3 root root 17 3月 1 09:28 systemd-private-1adb681dede84276b650ea38bfa4dc1d-chronyd.service-y66NBd
drwx------ 3 root root 17 3月 6 09:55 systemd-private-1adb681dede84276b650ea38bfa4dc1d-nginx.service-MgTlBE
#

详细说明参见红帽官网的这篇blog New Red Hat Enterprise Linux 7 Security Feature: PrivateTmp

Nginx推荐的nginx.service的写法

Nginx官方建议的设置Nginx的文档NGINX systemd service file中推荐的nginx.service的设置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target

结合gem install passenger的默认路径/opt/nginx/,实际部署的时候,被修改成如下内容来写入/lib/systemd/system/nginx.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=The nginx HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/opt/nginx/sbin/nginx -t
ExecStart=/opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target

passenger_instance_registry_dir的default值

根据Passenger官方文档说明,Passenger使用passenger_instance_registry_dir这个参数,来指定存放passenger进程信息的目录。

Specifies the directory that Passenger should use for registering its current instance.

When Passenger starts up, it creates a temporary directory inside the instance registry directory. This temporary directory is called the instance directory. It contains all sorts of files that are important to that specific running Passenger instance, such as Unix domain socket files so that all the different Passenger processes can communicate with each other. Command line tools such as passenger-status use the files in this directory in order to query Passenger’s status.

该目录会被passenger-status命令用来获取Passenger的状态。

而根据Passenger官方的介绍,passenger_instance_registry_dir参数默认的值是/tmp|/var/run/passenger-instreg

  • 如果是Red Hat and CentOS,并且是通过Phusion的yum源安装的,那么默认值是/var/run/passenger-instreg
  • 其他情况下,默认值是$TMPDIR环境变量的值,如果$TMPDIR没有设置,那么就是/tmp

如果没有使用默认路径,那么运行passenger-status之前,就需要使用export PASSENGER_INSTANCE_REGISTRY_DIR=/my_temp-dir来声明registry dir。

原因

了解了相关的原理,就很清晰地知道passenger-status运行不成功的原因了。
Nginx推荐的nginx.service脚本中,PrivateTmp是true的,passenger的进程信息就被系统放在了/tmp/systemd-private-xxxx的目录中了。而passenger-status还是去默认的/tmp下去寻找passenger进程状态,导致了命令运行失败。

解决方案

两个解决办法也就一目了然了。

  • 修改nginx.service的PrivateTmp值
  • 修改passenger_instance_registry_dir

修改PrivateTmp

第一个简单的办法就是修改nginx.service的PrivateTmp为false。

此时,禁用了systemd的private tmp的隔离机制,passenger的进程信息会被写入/tmp/目录,passenger-status命令就能够获取passenger运行信息并输出了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=The nginx HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/opt/nginx/sbin/nginx -t
ExecStart=/opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=false
[Install]
WantedBy=multi-user.target

重新load nginx.service并重启nginx.service

1
2
3
4
5
# reload the nginx.service
systemctl daemon-reload
# restart the nginx
systemctl restart nginx.service

/tmp下就可以看到passenger的信息目录,passenger-status命令也就可以输出passenger的状态了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ ll /tmp/
总用量 0
drwxr-xr-x 5 root root 223 3月 10 09:20 passenger.wRvwBR0
drwx------ 3 root root 17 3月 1 09:28 systemd-private-1adb681dede84276b650ea38bfa4dc1d-chronyd.service-y66NBd
$
$ passenger-status
Version : 5.3.7
Date : 2019-03-10 09:23:15 +0000
Instance: 9NWwyPOn (nginx/1.14.0 Phusion_Passenger/5.3.7)
----------- General information -----------
Max pool size : 6
App groups : 0
Processes : 0
Requests in top-level queue : 0
----------- Application groups -----------
$

指定passenger_instance_registry_dir

按照上文所述的官方文档的说明,理论上运行passenger-status时,指定正确的passenger_instance_registry_dir,即可成功执行。

但实际执行中,在CentOS 7下,在nginx.servicePrivateTmp=true的情况下,因为路径过长,会报too long unix socket path的错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ export PASSENGER_INSTANCE_REGISTRY_DIR=/tmp/systemd-private-1adb681dede84276b650ea38bfa4dc1d-nginx.service-xrbYa5/tmp/
$ passenger-status
Version : 5.3.7
Date : 2019-03-10 09:37:36 +0000
Instance: wbr6WsVE (nginx/1.14.0 Phusion_Passenger/5.3.7)
/usr/local/rvm/gems/ruby-2.3.7/gems/passenger-5.3.7/src/ruby_supportlib/phusion_passenger/admin_tools/instance.rb:94:in `initialize': too long unix socket path (115bytes given but 108bytes max) (ArgumentError)
from /usr/local/rvm/gems/ruby-2.3.7/gems/passenger-5.3.7/src/ruby_supportlib/phusion_passenger/admin_tools/instance.rb:94:in `new'
from /usr/local/rvm/gems/ruby-2.3.7/gems/passenger-5.3.7/src/ruby_supportlib/phusion_passenger/admin_tools/instance.rb:94:in `http_request'
from /usr/local/rvm/gems/ruby-2.3.7/gems/passenger-5.3.7/bin/passenger-status:113:in `show_status'
from /usr/local/rvm/gems/ruby-2.3.7/gems/passenger-5.3.7/bin/passenger-status:61:in `command_show_status'
from /usr/local/rvm/gems/ruby-2.3.7/gems/passenger-5.3.7/bin/passenger-status:332:in `start'
from /usr/local/rvm/gems/ruby-2.3.7/gems/passenger-5.3.7/bin/passenger-status:335:in `<top (required)>'
from /usr/local/rvm/gems/ruby-2.3.7/bin/passenger-status:23:in `load'
from /usr/local/rvm/gems/ruby-2.3.7/bin/passenger-status:23:in `<main>'
from /usr/local/rvm/gems/ruby-2.3.7/bin/ruby_executable_hooks:24:in `eval'
from /usr/local/rvm/gems/ruby-2.3.7/bin/ruby_executable_hooks:24:in `<main>'
$

sock path length是Linux系统的限制。具体可以参考Why is socket path length limited to a hundred chars?这篇文章。

既然替换为systemd的privatetmp的路径不可行,那么换个思路,可在Passenger启动的时候, 在配置文件中手动指定passenger注册实例的目录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建新的注册目录
$ sudo mkdir /opt/nginx/tmp
# 打开nginx配置文件,添加passenger_instance_registry_dir
$ sudo vim /opt/nginx/conf/nginx.conf
http {
......
passenger_instance_registry_dir /opt/nginx/tmp;
......
}
# 重启nginx
sudo systemctl restart nginx.service

再在执行passenger-status的时候,添加上registry_dir的路径。就可以顺利执行命令了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ export PASSENGER_INSTANCE_REGISTRY_DIR=/opt/nginx/tmp/
$ passenger-status
Version : 5.3.7
Date : 2019-03-10 10:02:15 +0000
Instance: inceochh (nginx/1.14.0 Phusion_Passenger/5.3.7)
----------- General information -----------
Max pool size : 6
App groups : 0
Processes : 0
Requests in top-level queue : 0
----------- Application groups -----------
$

Reference

留言