How to Use Separate PHP-FPM Pools for Hosting Multiple Sites on Nginx
As modern server hardware becomes increasingly powerful and resource-efficient, hosting multiple sites on a single Nginx instance has become a practical standard. For improved speed, better isolation, and enhanced security, it’s wise to assign individual PHP-FPM pools to each site. This guide walks you through setting up distinct PHP-FPM pools on an Ubuntu 20.04 LTS cloud server with PHP 7.4 and Nginx, allowing multiple virtual hosts to run on a single system.
Prerequisites
- Establish a sudo-enabled user without root privileges.
- Ensure your Ubuntu system is fully updated.
- Install a complete LEMP stack on Ubuntu 20.04 LTS.
- Create two “A” DNS records pointing to the same IP address, but with different hostnames — for example,
site1.example.com
andsite2.example.com
.
1. Delete the Default Nginx Site
Nginx ships with a default virtual host, which is unnecessary for our setup. Remove it by logging in as your sudo user and executing:
$ sudo rm /etc/nginx/sites-enabled/default
2. Set Up Dedicated Site Users
To enforce security boundaries, assign each site its own Unix user. These users should be isolated and without login rights. You’ll also add the web server user to each group:
$ sudo useradd site1
$ sudo useradd site2
$ usermod -a -G site1 www-data
$ usermod -a -G site2 www-data
3. Define Folder Permissions
Create directories for both websites and restrict access accordingly to prevent cross-site access:
$ sudo mkdir /var/www/site1
$ sudo chown -R site1:site1 /var/www/site1
$ sudo mkdir /var/www/site2
$ sudo chown -R site2:site2 /var/www/site2
$ sudo chmod 770 /var/www/site2
These permissions (770) give full access to the owner and group but restrict all others, ensuring separation between the two environments.
4. Duplicate the PHP-FPM Configuration
Use the default pool as a base and copy it for each individual site. Then, eliminate the original:
$ sudo cp /etc/php/7.4/fpm/pool.d/www.conf /etc/php/7.4/fpm/pool.d/fpm-site1.conf
$ sudo cp /etc/php/7.4/fpm/pool.d/www.conf /etc/php/7.4/fpm/pool.d/fpm-site2.conf
$ sudo rm /etc/php/7.4/fpm/pool.d/www.conf
5. Customize the First PHP-FPM Pool
Edit the configuration file for site1’s pool and modify these four parameters:
$ sudo nano /etc/php/7.4/fpm/pool.d/fpm-site1.conf
- Change
[www]
to[site1]
. - Update
user = www-data
touser = site1
. - Update
group = www-data
togroup = site1
. - Replace
listen = /var/run/php/php7.4-fpm.sock
withlisten = /var/run/php/php7.4-site1-fpm.sock
.
6. Customize the Second PHP-FPM Pool
Repeat the editing steps for site2’s pool configuration:
$ sudo nano /etc/php/7.4/fpm/pool.d/fpm-site2.conf
- Change
[www]
to[site2]
. - Update
user = www-data
touser = site2
. - Update
group = www-data
togroup = site2
. - Replace
listen = /var/run/php/php7.4-fpm.sock
withlisten = /var/run/php/php7.4-site2-fpm.sock
.
7. Restart PHP-FPM
Apply all the changes by restarting the PHP-FPM service:
$ sudo service php7.4-fpm restart
Confirm that the pools are running independently:
$ sudo service php7.4-fpm status
You should see separate processes for each configured pool in the output, similar to:
CGroup: /system.slice/php7.4-fpm.service
├─70796 php-fpm: master process (/etc/php/7.4/fpm/php-fpm.conf)
├─70807 php-fpm: pool site1
├─70808 php-fpm: pool site1
├─70809 php-fpm: pool site2
└─70810 php-fpm: pool site2
Note: Process IDs will vary depending on your system’s runtime state.
8. Configure Nginx to Use the Dedicated PHP-FPM Pools
To ensure each website uses its corresponding PHP-FPM pool, you must define separate server configurations for each domain in Nginx.
Create Configuration for site1
Begin by creating a new Nginx site configuration file:
$ sudo nano /etc/nginx/sites-available/site1
Add the following configuration:
server {
server_name site1.example.com;
access_log /var/log/nginx/site1.access.log;
error_log /var/log/nginx/site1.error.log;
root /var/www/site1;
index index.php;
try_files $uri $uri/ /index.php?$query_string;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm-site1.sock;
include snippets/fastcgi-php.conf;
}
}
Explanation of the main directives:
- server_name: Defines the domain name for the virtual host.
- access_log: Specifies the file to store access logs.
- error_log: Sets the file path for error logs.
- root: Indicates the document root for site files.
- fastcgi_pass: Points to the PHP-FPM socket defined in the site’s pool.
Create Configuration for site2
Repeat the process for the second domain:
$ sudo nano /etc/nginx/sites-available/site2
Insert this configuration:
server {
server_name site2.example.com;
access_log /var/log/nginx/site2.access.log;
error_log /var/log/nginx/site2.error.log;
root /var/www/site2;
index index.php;
try_files $uri $uri/ /index.php?$query_string;
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm-site2.sock;
include snippets/fastcgi-php.conf;
}
}
Enable the New Site Configurations
Activate both configurations by creating symbolic links:
$ sudo ln -s /etc/nginx/sites-available/site1 /etc/nginx/sites-enabled/site1
$ sudo ln -s /etc/nginx/sites-available/site2 /etc/nginx/sites-enabled/site2
Reload Nginx to apply the changes:
$ sudo service nginx restart
9. Verify Site Isolation and Configuration
To ensure the setup works as expected, create a test PHP file for each site that outputs the PHP environment.
Create a PHP Info File for site1
$ nano /var/www/site1/index.php
Insert the following code:
<?php
phpinfo();
Create a PHP Info File for site2
$ nano /var/www/site2/index.php
Paste the same content:
<?php
phpinfo();
Visit http://site1.example.com
and http://site2.example.com
in a web browser to confirm that both domains serve their respective PHP-FPM pools. Check the PHP info output — under the PHP Variables section, the $_SERVER['USER']
value should be site1
for site1 and site2
for site2.
Conclusion
By allocating a unique PHP-FPM pool for every hosted domain, you enhance both security and performance. This also simplifies issue tracking and tuning of individual websites. All settings are stored within each pool’s file under /etc/php/7.4/fpm/pool.d
. One commonly modified setting is pm
, which controls how PHP-FPM manages child processes. You can configure this parameter with modes like dynamic, static, or ondemand depending on your server’s resource usage. Refer to the official PHP-FPM documentation for further details on pool configuration.