How to Configure PHP-FPM with Nginx on RHEL 7
PHP-FPM (FastCGI Process Manager) is the recommended way to run PHP alongside Nginx. Unlike Apache’s mod_php which embeds PHP directly into the web server process, PHP-FPM runs as a completely separate daemon. Nginx passes PHP requests to PHP-FPM over a Unix socket or TCP connection, and PHP-FPM manages a pool of worker processes to handle them. This separation has significant advantages: PHP-FPM can run under a different user than Nginx for improved security isolation, worker processes can be recycled to prevent memory leaks, and the pool configuration gives you fine-grained control over concurrency and resource usage. This guide covers the complete configuration of PHP-FPM and Nginx on RHEL 7, from pool setup and socket configuration through process management strategies, the PHP-FPM status page, and slow log debugging.
Prerequisites
- RHEL 7 server with root or sudo access
- PHP 7.4 installed from the Remi repository including the
php-fpmpackage - Nginx installed and running
- Basic familiarity with
systemctlandvior another text editor
Step 1: Verify PHP-FPM is Installed
Confirm the php-fpm package is installed:
rpm -q php-fpm
If not installed, add it:
sudo yum install -y php-fpm
Check the version and confirm it matches your installed PHP:
php-fpm -v
Step 2: Understand PHP-FPM Configuration Files
PHP-FPM’s configuration is split across two locations:
/etc/php-fpm.conf— Global PHP-FPM settings (log file, pid file, emergency restart thresholds)/etc/php-fpm.d/*.conf— Pool definition files, one per pool; the default pool iswww.conf
View the default pool file:
sudo cat /etc/php-fpm.d/www.conf
The pool file controls everything about how PHP-FPM handles requests for that pool: which user runs the workers, where to listen, how many processes to maintain, and what resource limits to apply.
Step 3: Configure the PHP-FPM Pool
Open the default pool configuration for editing:
sudo vi /etc/php-fpm.d/www.conf
User and Group
PHP-FPM worker processes should run as the same user as Nginx to allow the socket to be accessed. On RHEL 7 with Nginx from the base repository, this is the nginx user:
user = nginx
group = nginx
Listen — Unix Socket vs TCP
PHP-FPM can accept connections over a Unix domain socket (recommended when Nginx and PHP-FPM are on the same server) or a TCP socket (required when they are on different servers):
; Unix socket — faster, recommended for same-server setups
listen = /run/php-fpm/www.sock
; TCP — use when Nginx is on a separate host
; listen = 127.0.0.1:9000
When using a Unix socket, set the socket permissions so Nginx can connect to it:
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
When using TCP, no socket permission settings are needed, but ensure a firewall allows the port if Nginx is remote.
Process Management Modes
The pm directive controls how PHP-FPM manages worker processes. Three modes are available:
; static: Always keeps a fixed number of workers running
; Best for high-traffic, predictable workloads with sufficient RAM
pm = static
pm.max_children = 20
; dynamic: Adjusts the number of workers based on current load
; Best for servers with variable traffic or limited RAM
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 20
; ondemand: Spawns workers only when requests arrive, kills idle ones
; Best for low-traffic servers or many pools on one machine
pm = ondemand
pm.max_children = 20
pm.process_idle_timeout = 10s
For most production web servers, dynamic is the recommended mode. A good rule of thumb for sizing pm.max_children is:
pm.max_children = (Total RAM - OS overhead) / Average PHP process memory
Check the average memory used by current PHP-FPM workers:
ps --no-headers -o "rss,cmd" -C php-fpm | awk '{sum+=$1} END {print int(sum/NR/1024) "MB average"}'
Request and Worker Limits
; Restart a worker after this many requests (prevents memory leaks)
pm.max_requests = 500
; Maximum time a request may take before the worker is killed (seconds)
request_terminate_timeout = 60
; Maximum time before a slow request is logged (0 = disabled)
; Set this to enable the slow log
request_slowlog_timeout = 5s
Step 4: Configure the PHP-FPM Slow Log
The slow log records stack traces for requests that take longer than request_slowlog_timeout to complete. It is invaluable for identifying performance bottlenecks:
; Path to the slow log file
slowlog = /var/log/php-fpm/www-slow.log
; Log requests taking longer than this (5 seconds in this example)
request_slowlog_timeout = 5s
Create the log directory if it does not exist:
sudo mkdir -p /var/log/php-fpm
sudo chown nginx:nginx /var/log/php-fpm
When a slow request is detected, the slow log will contain output similar to this:
[17-May-2026 14:32:01] [pool www] pid 12345
script_filename = /var/www/myapp/public/index.php
[0x00007f3d4c009f60] mysqli_query() /var/www/myapp/app/Models/User.php:87
[0x00007f3d4c009e40] getUser() /var/www/myapp/app/Controllers/HomeController.php:43
[0x00007f3d4c009d30] index() /var/www/myapp/public/index.php:22
Step 5: Enable the PHP-FPM Status Page
PHP-FPM exposes a real-time status endpoint that shows active workers, accepted connections, and queue depth. Enable it in the pool configuration:
; Status page URI — must start with /
pm.status_path = /fpm-status
; Ping endpoint for health checks
ping.path = /fpm-ping
ping.response = pong
Step 6: Start and Enable PHP-FPM
Save the pool configuration. Enable and start the PHP-FPM service:
sudo systemctl enable php-fpm
sudo systemctl start php-fpm
Confirm it started without errors:
sudo systemctl status php-fpm
Verify the socket file was created with the correct ownership:
ls -la /run/php-fpm/www.sock
Step 7: Configure Nginx to Pass PHP Requests to PHP-FPM
Create or update your Nginx virtual host configuration to forward .php requests to the PHP-FPM socket:
sudo vi /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name yourdomain.com;
root /var/www/html;
index index.php index.html;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
try_files $uri $uri/ =404;
}
# Pass PHP files to PHP-FPM via Unix socket
location ~ .php$ {
# Mitigate PATH_INFO security issue
try_files $uri =404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
# Connect to the PHP-FPM socket
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_index index.php;
# CRITICAL: tells PHP-FPM which file to execute
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Include standard FastCGI parameters
include fastcgi_params;
# Increase timeout for long-running scripts
fastcgi_read_timeout 300;
# Buffer settings
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}
# Expose the PHP-FPM status page — restrict to localhost
location ~ ^/(fpm-status|fpm-ping)$ {
allow 127.0.0.1;
deny all;
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Test the configuration and reload Nginx:
sudo nginx -t
sudo systemctl reload nginx
Step 8: Verify the FastCGI Configuration
The fastcgi_params file that Nginx includes by default (/etc/nginx/fastcgi_params) sets most FastCGI variables, but the most important one — SCRIPT_FILENAME — must be set explicitly. Confirm it is in your config:
grep SCRIPT_FILENAME /etc/nginx/conf.d/default.conf
Without a correct SCRIPT_FILENAME, PHP-FPM will not know which script to execute and will return a blank page or error.
Step 9: Test PHP Processing and View the Status Page
Create a PHP test file:
sudo bash -c 'echo "<?php echo phpinfo(); ?>" > /var/www/html/test.php'
Access it in a browser at http://yourdomain.com/test.php to confirm PHP is processing. Remove it after testing.
Access the PHP-FPM status page from the server itself:
curl http://127.0.0.1/fpm-status
Example output:
pool: www
process manager: dynamic
start time: 17/May/2026:10:00:00 +0000
start since: 3600
accepted conn: 1482
listen queue: 0
max listen queue: 0
listen queue len: 0
idle processes: 5
active processes: 1
total processes: 6
max active processes: 8
max children reached: 0
slow requests: 2
For a JSON response suitable for monitoring systems:
curl http://127.0.0.1/fpm-status?json
Check the ping endpoint for simple health checks:
curl http://127.0.0.1/fpm-ping
Step 10: Graceful Reload and Log Rotation
After any changes to php.ini or pool configuration files, reload PHP-FPM gracefully. This finishes in-flight requests before restarting workers:
sudo systemctl reload php-fpm
PHP-FPM integrates with logrotate. The default log rotation configuration is at /etc/logrotate.d/php-fpm. After log rotation, send USR1 to PHP-FPM to reopen log file handles:
sudo kill -USR1 $(cat /var/run/php-fpm/php-fpm.pid)
Conclusion
PHP-FPM is now fully configured to work with Nginx on RHEL 7 using a Unix domain socket, with dynamic process management tuned to balance memory usage and concurrency. The slow log will capture stack traces for requests exceeding five seconds, the status endpoint provides real-time operational metrics, and SCRIPT_FILENAME is correctly set so PHP-FPM knows exactly which file Nginx is requesting. This architecture is the standard production setup for PHP applications on RHEL 7 — it is secure, efficient, and easily extended to support multiple application pools by creating additional .conf files in /etc/php-fpm.d/, each listening on its own socket with its own user, process limits, and PHP settings.