Nginx + PHP-FPM with chroot
This document covers the process of setting up Nginx and PHP-FPM, with the latter running in chroot mode. It is assumed that the reader is familiar with what chroot is and its limitations.
These instructions were tested on a freshly installed Debian GNU/Linux (Wheezy, 7.7) system and require root privileges.
Introduction
Using chroot is useful where you would like to restrict PHP code from accessing files outside of a specific directory. This is especially useful if you allow other people to upload PHP code to your server (for example by hosting a WordPress instance for your friends or customers and allowing them to edit their custom theme).
The steps below shows how to configure an FPM pool (with chroot enabled) that is shared by two domains for a single imaginary customer "example.com".
Please note that this is not the most secure configuration – in practice it would be better to have a pool per domain, if your server resources allow it.
Install the packages
aptitude -q update
aptitude -q install nginx php5-fpm
Create web data directories
mkdir -p /srv/www/chroot-example.com/host1
mkdir -p /srv/www/chroot-example.com/host2
Add some sample content
cat << 'EOF' > /srv/www/chroot-example.com/host1/index.php
<?php
echo "<p>This is <b>host1.example.com</b></p>\n";
echo '<p>Current working directory is <b>' . getcwd() . "</b></p>\n";
EOF
cat << 'EOF' > /srv/www/chroot-example.com/host2/index.php
<?php
echo "<p>This is <b>host2.example.com</b></p>\n";
echo '<p>Current working directory is <b>' . getcwd() . "</b></p>\n";
EOF
Configure Nginx
cat << 'EOF' > /etc/nginx/sites-enabled/host1.example.com
server {
listen 80;
server_name host1.example.com;
access_log /var/log/nginx/host1.example.com-access.log;
error_log /var/log/nginx/host1.example.com-error.log;
server_tokens off;
root /srv/www/chroot-example.com/host1;
index index.php;
location ~ /\.ht {deny all;}
location ~ \.php$ {
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /host1$fastcgi_script_name;
fastcgi_pass unix:/var/run/php5-fpm-chroot-example.com.sock;
try_files $uri =404;
}
}
EOF
cat << 'EOF' > /etc/nginx/sites-enabled/host2.example.com
server {
listen 80;
server_name host2.example.com;
access_log /var/log/nginx/host2.example.com-access.log;
error_log /var/log/nginx/host2.example.com-error.log;
server_tokens off;
root /srv/www/chroot-example.com/host2;
index index.php;
location ~ /\.ht {deny all;}
location ~ \.php$ {
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /host2$fastcgi_script_name;
fastcgi_pass unix:/var/run/php5-fpm-chroot-example.com.sock;
try_files $uri =404;
}
}
EOF
Configure PHP-FPM
cat << 'EOF' > /etc/php5/fpm/pool.d/chroot-example.com.conf
[chroot-example.com]
; OUR CUSTOM SETTINGS
listen = /var/run/php5-fpm-chroot-example.com.sock
prefix = /srv/www/chroot-example.com
chroot = $prefix
; DEFAULT DEBIAN SETTINGS
chdir = /
user = www-data
group = www-data
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
EOF
Restart services
service php5-fpm restart
nginx -t && service nginx restart
Testing
root@debian-wheezy:~# wget -q -O - http://host1.example.com
<p>This is <b>host1.example.com</b></p>
<p>Current working directory is <b>/host1</b></p>
root@debian-wheezy:~# wget -q -O - http://host2.example.com
<p>This is <b>host2.example.com</b></p>
<p>Current working directory is <b>/host2</b></p>
And we’re done! :)
Disclaimer
The information above is accurate to my knowledge, however I provide no guarantees to this effect and consequently accept no liability whatsoever for any bad things that may happen as a result of the reader using this information in practice. Use at your own risk. Oh, and backup your data while you’re at it.