1,PHP的chroot配置
有时候开启了chroot的项目,偶尔请求外部域名,会有报错,反馈77的code,一般就是里边依赖库的问题,重新执行一波下边的操作即可。
一些目录的创建
mkdir -p /data/www
mkdir /data/www/usr/
mkdir /data/www/usr/local/
mkdir /data/www/etc/
mkdir /data/www/usr/share/zoneinfo/Asia/
rsync -al /dev/null /data/www/dev/
rsync -al /dev/random /data/www/dev/
rsync -al /dev/urandom /data/www/dev/
rsync -al /dev/zero /data/www/dev/
rsync -al /lib /data/www/
rsync -al /lib64 /data/www/
rsync -al /usr/lib /data/www/usr/
rsync -al /usr/lib64 /data/www/usr/
rsync -al /usr/local/lib /data/www/usr/local/
rsync -al /usr/local/lib64 /data/www/usr/local/
rsync -al /etc/pki /data/www/etc/
rsync -al /etc/ssl /data/www/etc/
rsync -al /etc/resolv.conf /data/www/etc/
rsync -al /usr/share/zoneinfo/Asia/Shanghai /data/www/usr/share/zoneinfo/Asia/
mkdir /data/www/tmp
chmod 1777 /data/www/tmp
另外一种方式可通过本机挂载来设置:
原来:
rsync -al /dev/null /data/www/dev/
rsync -al /dev/random /data/www/dev/
rsync -al /dev/urandom /data/www/dev/
rsync -al /dev/zero /data/www/dev/
rsync -al /lib /data/www/
rsync -al /lib64 /data/www/
rsync -al /usr/lib /data/www/usr/
rsync -al /usr/lib64 /data/www/usr/
rsync -al /usr/local/lib /data/www/usr/local/
rsync -al /usr/local/lib64 /data/www/usr/local/
rsync -al /etc/pki /data/www/etc/
rsync -al /etc/ssl /data/www/etc/
rsync -al /etc/resolv.conf /data/www/etc/
rsync -al /usr/share/zoneinfo/Asia/Shanghai /data/www/usr/share/zoneinfo/Asia/
现在:
mkdir -p /data/www/dev
mkdir -p /data/www/lib
mkdir -p /data/www/lib64
mkdir -p /data/www/usr/lib
mkdir -p /data/www/usr/lib64
mkdir -p /data/www/etc
mkdir -p /data/www/usr/share/zoneinfo/Asia
mount --bind -o ro /dev /data/www/dev/
mount --bind -o ro /lib /data/www/lib
mount --bind -o ro /lib64 /data/www/lib64
mount --bind -o ro /usr/lib /data/www/usr/lib
mount --bind -o ro /usr/lib64 /data/www/usr/lib64
mount --bind -o ro /etc /data/www/etc
mount --bind -o ro /usr/share/zoneinfo/Asia /data/www/usr/share/zoneinfo/Asia
然后是PHP的配置文件更改/usr/local/php/etc/php-fpm.d/www.conf
[chroot]
listen = 127.0.0.1:9000
user = www
group = www
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 100
request_terminate_timeout = 120
request_slowlog_timeout = 2
slowlog = /var/log/php-fpm/chroot-slow.log
chroot = /data/www
php_admin_value[error_log] = /var/log/php-fpm/chroot-error.log
php_admin_flag[log_errors] = on
php_value[session.save_path] = /var/lib/php/session
此时PHP配置完成之后,可以创建一个PHP文件进行验证。
当我进行验证的时候发现,死活不能得到想要的结果,一直会报一个 "File not found"
内容,看NGINX的错误日志内容如下:
2019/08/02 15:59:18 [error] 19008#0: *341 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 115.238.43.130, server: localhost, request: "GET / HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "115.159.112.87", referrer: "http://115.159.112.87/"
2,NGINX配置。
这个时候我的NGINX配置为:
server {
listen 80;
server_name localhost;
index index.html index.htm index.php default.html default.htm default.php;
root /data/www/typecho;
location ~ .*\.php(\/.*)*$ {
root /data/www/typecho;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
include pathinfo.conf;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 30d;
}
location ~ .*\.(js|css)?$ {
expires 12h;
}
}
如上配置在PHP不开启chroot的情况下,访问是没有问题的,只要一开启,就会报刚刚的错误。
后来查资料,了解到,当我设置了chroot,就相当于把配置的目录定义为了根目录,于是,在NGINX层面,就不能再像原来那样配置了。
也就是chroot目录定义为了 /data/www
,那么在php解析的时候,就需要将真实的项目目录定义为根目录才行,因此使用如下配置即可解决:
server {
listen 80;
server_name localhost;
index index.html index.htm index.php default.html default.htm default.php;
root /data/www/typecho;
location ~ .*\.php(\/.*)*$ {
root /data/www/typecho;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /typecho$fastcgi_script_name;
include fastcgi_params;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
expires 30d;
}
location ~ .*\.(js|css)?$ {
expires 12h;
}
}
其中 fastcgi_param SCRIPT_FILENAME /typecho$fastcgi_script_name;
的 /typecho
就是当前项目的根目录,然后再去访问,就没有问题了。
网上有说把配置定义为 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
也可以,但经过我的测试,发现并不行。
3,通过mount挂载扩展
这是一个有意思的尝试方案,仅作为扩展眼界,不太推荐生产使用。
我们可以通过mount –bind命令来将两个目录连接起来,mount –bind命令是将前一个目录挂载到后一个目录上,所有对后一个目录的访问其实都是对前一个目录的访问,如下所示:
# 将test1挂载到test2
mount --bind test1 test2
当mount –bind命令执行后,Linux将会把被挂载目录的目录项(也就是该目录文件的block,记录了下级目录的信息)屏蔽,即test2的下级路径被隐藏起来了(注意,只是隐藏不是删除,数据都没有改变,只是访问不到了)。同时,内核将挂载目录(test1)的目录项记录在内存里的一个s_root对象里,在mount命令执行时,VFS会创建一个vfsmount对象,这个对象里包含了整个文件系统所有的mount信息,其中也会包括本次mount中的信息,这个对象是一个HASH值对应表(HASH值通过对路径字符串的计算得来),表里就有 /test1 到 /test2 两个目录的HASH值对应关系。
命令执行完后,当访问 /test2下的文件时,系统会告知 /test2 的目录项被屏蔽掉了,自动转到内存里找VFS,通过vfsmount了解到 /test2 和 /test1 的对应关系,从而读取到 /test1 的inode,这样在 /test2 下读到的全是 /test1 目录下的文件。
- mount –bind连接的两个目录的inode号码并不一样,只是被挂载目录的block被屏蔽掉,inode被重定向到挂载目录的inode(被挂载目录的inode和block依然没变)。
- 两个目录的对应关系存在于内存里,一旦重启挂载关系就不存在了。
在固件开发过程中常常遇到这样的情况:为测试某个新功能,必需修改某个系统文件。而这个文件在只读文件系统上(总不能为一个小小的测试就重刷固件吧),或者是虽然文件可写,但是自己对这个改动没有把握,不愿意直接修改。这时候mount –bind就是你的好帮手。
假设我们要改的文件是/etc/hosts,可按下面的步骤操作:
- 把新的hosts文件放在/tmp下。当然也可放在硬盘或U盘上。
- mount –bind /tmp/hosts /etc/hosts 此时的/etc目录是可写的,所做修改不会应用到原来的/etc目录,可以放心测试。测试完成了执行 umount /etc/hosts 断开绑定。
解决重启挂载失效的问题:
当然是写入到自动挂载咯,写法如下:
$ cat /etc/fstab
/etc /data/www/etc none bind 0 0
/dev /data/www/dev/ none bind 0 0
/lib /data/www/lib none bind 0 0
/lib64 /data/www/lib64 none bind 0 0
/usr/lib /data/www/usr/lib none bind 0 0
/usr/lib64 /data/www/usr/lib64 none bind 0 0
/usr/share/zoneinfo/Asia /data/www/usr/share/zoneinfo/Asia none bind 0 0
或者使用另外一种方案,将这波挂载集成为一个服务,并把服务做成开机自启,并记得PHP的启动在此服务之后即可。
创建启动文件:
$ cat /etc/init.d/chroot_mount
#!/bin/sh
### BEGIN INIT INFO
# Provides: php7-fpm-chroot-setup
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Bind-mounts needed running before php-fpm.service
### END INIT INFO
CHROOT=/data/www
DIRS="/dev /lib /lib64 /usr/lib /usr/lib64 /etc /usr/share/zoneinfo/Asia"
case "$1" in
start)
$0 stop 2>/dev/null
for d in $DIRS; do
mkdir -p "${CHROOT}${d}"
mount --bind -o ro "${d}" "${CHROOT}${d}"
done
;;
stop)
for d in $DIRS; do
umount "${CHROOT}${d}"
done
;;
*)
echo "Usage: $N {start|stop}" >&2
exit 1
;;
esac
exit 0
添加为系统服务并启动,启动之前保证 /data/www
将要挂载的几个目录干净。
chmod +x chroot_mount
chkconfig --add chroot_mount
systemctl start chroot_mount
systemctl enable chroot_mount
然后调整一下php的启动文件:
$ vim php-fpm.service
[Unit]
Description=The PHP FastCGI Process Manager
After=network.target chroot_mount
[Service]
Type=simple
PIDFile=/var/run/php-fpm.pid
ExecStart=/usr/local/php/sbin/php-fpm --nodaemonize --fpm-config /usr/local/php/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
[Install]
WantedBy=multi-user.target
