为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

必须要编辑的重要字段是:

  1. 池名称。它是位于顶部的 [www]。将其重命名为[mysite]
  2. prefix = /var/www/html/pools/$pool (请确保 /var/www/html/pools/mysite/目录存在,可写)
  3. 接下来,更改用户和组字段,并输入用户名和组以运行它。
    user = site1
    group = site1
  4. 更改套接字文件名。每个池都应该有自己独立的套接字。并且特定站点应该使用此特定套接字文件连接到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

彩蛋:更好的分离方法:

共享APC或OPcache:为什么多个PHP-FPM主机更好

为PHP-FPM和nginx设置多个进程池而安全地运行多个网站
标签: