NGINX and PHP FPM – general setup and performance issues using open_basedir

nginxopen-basedirphp-fpm

I want to configure an NGINX server, which is able to host multiple websites, which are seperated from each other, so vhosta can't access files from vhostb.

I installed a fresh Debian 7.5 server and installed NGINX and PHP FPM from the default debian packages.

Then I'll added 2 new users vhosta and vhostb and added the NGINX webserver user www-data to the group of each user.

Next I created the following directory structure.

   var/
    |---www/
    |---vhosta
         |---httpdocs (permissions 750 - owner: vhosta - group: vhosta)
    |---vhostb
         |---httpdocs (permissions 750 - owner: vhostb - group: vhostb)

I configured an individual PHP FPM pool for each virtual host to seperate the PHP processes for each virtual host. The configuration is as following (just showing for vhosta)

[vhosta]
listen = /var/run/php5-fpm-vhosta.sock
user = vhosta
group = vhosta
listen.owner = vhosta
listen.group = vhosta

From my knowledge, this configuration should seperate vhosta from accessing files in vhostb's httpdocs directory, since vhosta does not have access permissions to the httpdocs folder from vhosta. I verified this, by trying creating a simple PHP script in vhosta, which tries to access files in vhostb's httpdocs directory.

So far, so good. I installed a PHP application (CMS) in vhosta and did some performance testing with ApacheBench.

Generally, everything runs more smooth and fast than with Apache2 and I'll end up with the following result.

Requests per second:    31.62 [#/sec] (mean)
Time per request:       316.209 [ms] (mean)
Time per request:       31.621 [ms] (mean, across all concurrent requests)
Transfer rate:          430.58 [Kbytes/sec] received

Well, 31.62 requests per second is fine for me at this point.

Last I want to access restrict both vhosta and vhostb to a subset of directories, so they do not have access to other world readable system files. I do so, by using the PHP directive open_basedir.

I have added the following to each virtial hosts PHP FPM pool (just showing vhosta)

php_admin_value[open_basedir] = /var/www/vhosta/httpdocs/:/tmp/

Doing so, the vhosts should not be able to access e.g. /etc/passwd. I created a simple PHP script, which verifies, that the vhosts can't access files outside from the configured directories.

Finally, I repeated the performance test and end up with the following result.

Requests per second:    11.82 [#/sec] (mean)
Time per request:       8460.087 [ms] (mean)
Time per request:       84.601 [ms] (mean, across all concurrent requests)
Transfer rate:          161.18 [Kbytes/sec] received

It seems, that adding an open_basedir directive to the PHP FPM pool causes a big performance decreasement. Access times and the amount of requests per second is now fairly similar compared to a setup using Apache2 with mod_php.

My questions are as following:

  1. Can the setup I created be considered as "secure", so the individual vhosts can't access each other? If not, what is best practice to do so and what am I missing?

  2. Why does the performance decrease so much, when I use open_basedir? Or is it save to not use open_basedir, since files like /etc/passwd are world readable anyway?

Best Answer

If you really want them to not access anything real on the system, setup chroot for php-fpm, thus creating a "fake" /etc/passwd and so on. Or, even easier, use docker!

1) I'm not sure how you did setup the static files to be loaded from those vhosts, because they are not supposed to be loaded in this case, maybe only if you pass everything to php-fpm which opens you to other kind of attacks and degrades performance. Normally you would put permissions like this (considering that nginx is the user running the nginx process):

  • /var/vhosta : owner vhosta.nginx ; perm 750
  • /var/vhostb : owner vhostb.nginx ; perm 750

2) I am not 100% sure, however if you have a complex application that loads a huge amount of files, and your I/O does not provide good performance, then it may make sense. open_basedir restrictions do stuff like checking if the files are not a symlink or inside a symlink and so on, making a lot of I/O requests so raising the IOPS of your disk. One more reason to use docker or at least chroot.