为PHP-FPM和nginx设置多个进程池而安全地运行多个网站
在本文中,我们将向您展示在不同Linux用户的LEMP上运行站点的安全性和隔离性优势。这将通过为每个nginx服务器块(站点或虚拟主机)创建不同的php-fpm进程池来完成。
设置安全LEMP的原因
在常见的LEMP设置下,只有一个php-fpm进程池为同一用户下的所有站点运行所有PHP脚本。这带来两个主要问题:
- 如果一个nginx服务器块上的Web应用程序(即子域或单独的站点)受到攻击,此服务器上的所有站点也将受到影响。攻击者能够读取其他站点的配置文件,包括数据库详细信息,甚至可以更改其文件。
- 如果您想让用户访问服务器上的站点,您几乎可以访问所有站点。例如,您的开发人员需要处理开发环境。但是,即使拥有非常严格的文件权限,您仍然可以在相同的服务器上访问所有站点,包括您的主站点。
我们在这个服务器上设置了多个站点。Nginx通过单独的服务器块(也就是apache中的vhost)来处理这些问题。但是还需要另外一件事。每个站点上的Php应该使用自己的用户运行,而不是名为www-data的nginx普通用户。
使用自己的uid / gid运行每个站点更安全,更容易处理。如果所有站点都使用相同的用户运行,则一个站点上的php可以读取/写入其他用户的文件。这是一个安全问题。此外,拥有单独的用户可以获得诸如单独的crontabs,识别每个用户的进程等的能力等。
上述问题,我们可以在php-fpm中通过创建一个在每个站点的不同用户下运行的不同进程池来解决。
第1步 - 配置php-fpm独立进程池
Php-fpm创建并管理一个php进程池,也称为worker,它接收和服务器请求从web目录执行php文件。现在fpm可以运行多个独立的池,每个池都有自己的uid / gid。这实际上很容易设置。
现在我们将使用自己的php-fpm池和Linux用户创建第二个站点(site1.example.org)。
让我们从创建必要的用户开始。为了获得最佳隔离,新用户应该拥有自己的组。首先创建用户组site1
:
sudo groupadd site1
然后请创建属于该组的用户site1:
sudo useradd -g site1 site1
到目前为止,新用户site1没有密码,无法登录服务器。如果您需要为某人提供对此站点文件的直接访问权限,则应使用该命令为该用户创建密码sudo passwd site1
。使用新的用户/密码组合,用户可以通过ssh或sftp远程登录。
接下来,为site1创建一个新的php-fpm进程池。php-fpm池本质上只是一个普通的Linux进程,它在某个用户/组下运行并侦听Linux套接字。它也可以监听IP:端口组合,但这需要更多的服务器资源,并且它不是首选方法。
在ubuntu上,包含池配置文件的目录是 /etc/php/7.0/fpm/pool.d/
www.conf是
一个已存在的文件,可以将其复制以创建更多池配置文件。每个文件必须以.conf结尾才能被php fpm识别为池配置文件。
该文件很长,但从这样的开始。
; Start a new pool named 'www'.
; the variable $pool can we used in any directive and will be replaced by the
; pool name ('www' here)
[www]
; Per pool prefix
; It only applies on the following directives:
; - 'slowlog'
; - 'listen' (unixsocket)
; - 'chroot'
; - 'chdir'
; - 'php_values'
; - 'php_admin_values'
; When not set, the global prefix (or /usr) applies instead.
; Note: This directive can also be relative to the global prefix.
; Default Value: none
;prefix = /path/to/pools/$pool
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
; will be used.
user = enlightened
group = enlightened
; The address on which to accept FastCGI requests.
; Valid syntaxes are:
; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on
; a specific port;
; 'port' - to listen on a TCP socket to all addresses on a
; specific port;
; '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = /var/run/php7-fpm.sock
; Set listen(2) backlog.
; Default Value: 128 (-1 on FreeBSD and OpenBSD)
;listen.backlog = 128
因此,请创建此文件的副本,并将其命名为将使用此池的站点:/etc/php/7.0/fpm/pool.d/site1.conf。
您可以使用喜欢的编辑器执行此操作,如下所示:
sudo vim/etc/php/7.0/fpm/pool.d/site1.conf
必须要编辑的重要字段是:
- 池名称。它是位于顶部的
[www]
。将其重命名为[mysite]
。 -
prefix = /var/www/html/pools/$pool (请确保 /var/www/html/pools/mysite/目录存在,可写)
- 接下来,更改用户和组字段,并输入用户名和组以运行它。
user = site1group = site1
- 更改套接字文件名。每个池都应该有自己独立的套接字。并且特定站点应该使用此特定套接字文件连接到fpm。
listen = /run/php/php7.0-fpm-mysite.sock
完成上述配置后,重启php-fpm以使新设置生效
$ sudo service php7.0-fpm restart
通过搜索如下所示的进程来验证新池是否正常运行:
ps aux |grep site1
如果您已按照此处的确切说明进行操作,则应看到类似于以下内容的输出:site1 14042 0.0 0.8 133620 4208 ? S 14:45 0:00 php-fpm: pool site1
site1 14043 0.0 1.1 133760 5892 ? S 14:45 0:00 php-fpm: pool site1
红色是进程或php-fpm池运行的用户 - site1。有关所有配置参数的详细信息,请查看文档。每个池可以根据站点的需要具有不同的配置。
ps:其它一些可选设置:
listen.owner并listen.group定义侦听器的所有权,即新php-fpm池的套接字。Nginx必须能够读取此套接字。这就是为什么套接字是用nginx运行的用户和组创建的 - www-data。
php_admin_value,php_value允许您设置自定义php配置值。
php_admin_flag,php_flag类似于php_admin_value,但它只是布尔值的开关,即打开和关闭。
注意:以上php_admin_value和php_admin_flag值也可以全局应用。但是,站点可能需要它们,这就是为什么默认情况下它们没有配置。php-fpm池的优点在于它允许你微调每个站点的安全设置。此外,这些选项可用于安全范围之外的任何其他php设置,以进一步自定义站点的环境。
配置Nginx
一旦我们为我们的站点配置了php-fpm池,我们将在nginx中配置服务器块:
为此,请使用您喜欢的编辑器创建一个新文件/etc/nginx/sites-available/site1.conf,如下所示:
sudo vim /etc/nginx/sites-available/site1.conf
此文件中的PHP配置如下:
location ~ \.php(.*)$ {
fastcgi_pass unix:/var/run/php/php7.0-fpm-mysite.sock;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root:/var/www/html/site1:/tmp/:/proc/"; #禁止跨目录访问
include fastcgi_params;
}
上面将套接字描述符路径放在fastcgi_pass行中。
fastcgi_pass unix:/run/php/php7.0-fpm-mysite.sock;
。Nginx新站点现在将使用此套接字。
对于每个站点,应该使用不同的unix套接字,例如/var/run/php7.0-fpm-site2.sock
。
最后,重启nginx以使更改生效,如下所示:
sudo service nginx restart
enjoy it!
注意:另外需要开启php.ini中的 opcache.validate_permission和opcache.validate_root,否则还是会不安全。
结论
从安全的角度来看,对于同一个Nginx Web服务器上的每个站点,使用具有不同用户的php-fpm池至关重要。即使它带来了很小的性能损失,这种隔离的好处也可以防止严重的安全漏洞。
原创文章,如果转载请注明:来自Lenix的博客 ,地址 http://blog.p2hp.com/archives/5789
彩蛋:更好的分离方法: