PHP-FPM Plugin
Monitor PHP-FPM (FastCGI Process Manager) with comprehensive metrics covering process pools, request performance, slow requests, and resource usage.
Overview
The PHP-FPM plugin collects detailed metrics from PHP-FPM's status page including:
- Pool Status - Pool name, process manager type, start time
- Process Metrics - Active, idle, total processes
- Request Statistics - Accepted connections, request rate, slow requests
- Queue Metrics - Listen queue length, max listen queue
- Process Lifecycle - Max children reached, process limits
- Performance - Requests per process, average request duration
Requirements
PHP-FPM Version
- Minimum: PHP 7.4
- Recommended: PHP 8.1 or later
- Tested with: PHP 7.4, 8.0, 8.1, 8.2, 8.3
PHP-FPM Configuration
Status page must be enabled in PHP-FPM pool configuration.
Python Dependencies
No additional Python packages required - uses standard library urllib
.
Configuration
Basic Configuration
plugins:
php_fpm:
enabled: true
status_url: http://127.0.0.1:9000/status?json
With Custom Socket
plugins:
php_fpm:
enabled: true
status_url: http://unix:/run/php/php8.1-fpm.sock:/status?json
HTTP via Nginx/Apache
plugins:
php_fpm:
enabled: true
status_url: http://127.0.0.1:8080/fpm-status?json
All Configuration Options
plugins:
php_fpm:
enabled: true # Enable/disable plugin
status_url: http://127.0.0.1/status?json # Status URL
timeout: 10 # Request timeout (seconds)
format: json # Response format (json/text)
Environment Variables
Configuration can be overridden with environment variables:
export PHP_FPM_STATUS_URL="http://127.0.0.1:8080/status?json"
PHP-FPM Setup
Enable Status Page
Edit PHP-FPM pool configuration:
Ubuntu/Debian:
sudo nano /etc/php/8.1/fpm/pool.d/www.conf
CentOS/RHEL:
sudo nano /etc/php-fpm.d/www.conf
Enable status page:
; Enable status page
pm.status_path = /status
Optional - Enable ping page:
; Enable ping endpoint
ping.path = /ping
ping.response = pong
Restart PHP-FPM:
# Ubuntu/Debian
sudo systemctl restart php8.1-fpm
# CentOS/RHEL
sudo systemctl restart php-fpm
Nginx Configuration
Method 1: FastCGI via Socket
server {
listen 127.0.0.1:8080;
location ~ ^/(status|ping)$ {
access_log off;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# Security: only allow from localhost
allow 127.0.0.1;
deny all;
}
}
Method 2: FastCGI via TCP
server {
listen 127.0.0.1:8080;
location ~ ^/(status|ping)$ {
access_log off;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Reload Nginx:
sudo nginx -t && sudo systemctl reload nginx
Apache Configuration
Enable mod_proxy_fcgi:
sudo a2enmod proxy_fcgi
sudo systemctl restart apache2
Configure status endpoint:
<VirtualHost 127.0.0.1:8080>
<LocationMatch "^/(status|ping)$">
ProxyPass "unix:/run/php/php8.1-fpm.sock|fcgi://localhost/"
Require local
</LocationMatch>
</VirtualHost>
Security Considerations
Restrict access to localhost only:
Nginx:
location /status {
allow 127.0.0.1;
allow ::1;
deny all;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
include fastcgi_params;
}
Apache:
<Location /status>
Require local
</Location>
PHP-FPM pool config:
; Restrict allowed clients (if using TCP)
listen.allowed_clients = 127.0.0.1
Collected Metrics
Metric | Description | Unit | Type |
---|---|---|---|
pool |
Pool name (e.g., "www") | String | Info |
process_manager |
PM type (static/dynamic/ondemand) | String | Info |
start_time |
Pool start timestamp | Unix time | Gauge |
uptime_seconds |
Seconds since start | Seconds | Gauge |
accepted_connections |
Total accepted connections | Count | Counter |
listen_queue |
Current listen queue length | Count | Gauge |
max_listen_queue |
Max listen queue since start | Count | Gauge |
listen_queue_length |
Listen queue size limit | Count | Gauge |
idle_processes |
Idle processes | Count | Gauge |
active_processes |
Active processes | Count | Gauge |
total_processes |
Total processes | Count | Gauge |
max_active_processes |
Max active since start | Count | Gauge |
max_children_reached |
Times max children limit hit | Count | Counter |
slow_requests |
Slow requests count | Count | Counter |
Dashboard Metrics
The StatusRadar dashboard displays:
Overview Card
- Active Processes - Current active workers
- Idle Processes - Available workers
- Listen Queue - Queued requests
- Slow Requests - Performance issues
Process Pool Chart
- Total processes over time
- Active vs idle processes
- Process manager efficiency
Queue Metrics Chart
- Listen queue length
- Max queue reached
- Queue saturation
Request Rate Chart
- Accepted connections rate
- Requests per process
- Slow request rate
Process Limit Chart
- Max children reached events
- Process pool saturation
- Capacity planning
Installation
Quick Install
PLUGINS='php_fpm' \
TOKEN='your-agent-token' \
PHP_FPM_STATUS_URL='http://127.0.0.1:8080/status?json' \
bash -c "$(curl -sL https://statusradar.dev/install-agent.sh)"
Install on Existing Agent
-
Enable PHP-FPM status (see PHP-FPM Setup above)
-
Configure agent:
sudo nano /opt/statusradar/config/agent.yaml
Add:
plugins: php_fpm: enabled: true status_url: http://127.0.0.1:8080/status?json
-
Restart agent:
sudo systemctl restart statusradar-agent
-
Verify:
sudo journalctl -u statusradar-agent -n 50 --no-pager | grep php_fpm
Expected:
INFO: Plugin php_fpm: Metrics collected successfully INFO: Plugin php_fpm: Pool www, 5 active, 10 idle processes
Testing
Manual Plugin Test
cd /opt/statusradar
python3 plugins/php_fpm_plugin.py
Expected Output:
Plugin: php_fpm
Enabled: True
Available: True
Collecting metrics...
{
"pool": "www",
"process_manager": "dynamic",
"start_time": 1697457600,
"uptime_seconds": 86400,
"accepted_connections": 123456,
"listen_queue": 0,
"max_listen_queue": 5,
"listen_queue_length": 128,
"idle_processes": 10,
"active_processes": 5,
"total_processes": 15,
"max_active_processes": 12,
"max_children_reached": 2,
"slow_requests": 15
}
Test Status Endpoint
JSON format (recommended):
curl http://127.0.0.1:8080/status?json
Text format:
curl http://127.0.0.1:8080/status?full
Full process list:
curl http://127.0.0.1:8080/status?full&json
Test Ping Endpoint
curl http://127.0.0.1:8080/ping
# Expected: pong
Troubleshooting
Plugin Not Collecting Metrics
Check 1: Is PHP-FPM running?
sudo systemctl status php8.1-fpm # Ubuntu/Debian
sudo systemctl status php-fpm # CentOS/RHEL
Check 2: Is status page enabled?
# Check pool configuration
grep "pm.status_path" /etc/php/8.1/fpm/pool.d/www.conf
# Should show: pm.status_path = /status
Check 3: Is status endpoint accessible?
curl http://127.0.0.1:8080/status?json
# If connection refused, check Nginx/Apache config
# If 404, PHP-FPM status not enabled
Check 4: Check agent logs
sudo journalctl -u statusradar-agent -n 100 --no-pager | grep php_fpm
Common Errors
"Connection refused"
Error:
ERROR: Plugin php_fpm: Connection refused
Causes:
- Nginx/Apache not configured
- Wrong status_url
- PHP-FPM not listening on expected socket/port
Solution:
# Check PHP-FPM socket
sudo ls -la /run/php/
# Check Nginx is running
sudo systemctl status nginx
# Test status URL manually
curl -v http://127.0.0.1:8080/status?json
"404 Not Found"
Error:
ERROR: Plugin php_fpm: HTTP 404 - status page not found
Causes:
pm.status_path
not set in pool config- Nginx/Apache not configured to pass status requests
- Wrong URL path
Solution:
1. Enable in PHP-FPM pool:
pm.status_path = /status
2. Configure Nginx:
location /status {
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
include fastcgi_params;
}
3. Restart services:
sudo systemctl restart php8.1-fpm nginx
"Access denied"
Error:
ERROR: Plugin php_fpm: HTTP 403 - Access forbidden
Cause: IP restrictions blocking access
Solution:
location /status {
allow 127.0.0.1;
allow ::1;
deny all;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
include fastcgi_params;
}
"Invalid JSON response"
Error:
ERROR: Plugin php_fpm: Cannot parse JSON response
Cause: Missing ?json
parameter in URL
Solution:
plugins:
php_fpm:
status_url: http://127.0.0.1:8080/status?json # Add ?json
Performance Impact
On PHP-FPM
Minimal impact:
- Status endpoint returns pre-calculated statistics
- No PHP script execution
- Response time: < 1ms
Benchmark:
- Overhead: < 0.001% CPU
- No measurable performance degradation
On Agent
Resource usage:
- Memory: +8 MB
- CPU: +2% during collection
- Network: +1 KB per collection
Collection time: < 0.1 seconds
Use Cases
1. Process Pool Monitoring
Monitor:
- Active vs idle processes
- Process pool saturation
- Process manager efficiency
Alert on:
- Active processes > 90% of max
- No idle processes (saturation)
- Max children limit reached frequently
2. Queue Saturation
Monitor:
- Listen queue length
- Max listen queue reached
- Queue vs queue limit
Alert on:
- Listen queue > 0 (backlog building)
- Max queue size reached
- Queue approaching limit
3. Slow Request Detection
Monitor:
- Slow request count
- Slow request rate
- Slow request threshold
Alert on:
- Slow requests increasing
- Slow request rate > 1% of total
4. Capacity Planning
Monitor:
- Max active processes trend
- Max children reached count
- Process turnover rate
Use for:
- Determining optimal pm.max_children
- Scaling decisions
- Performance tuning
Best Practices
1. Choose Correct Process Manager
Static PM:
pm = static
pm.max_children = 50
- Pros: Predictable resource usage
- Cons: Always uses max memory
- Best for: Dedicated PHP servers, consistent load
Dynamic PM (recommended):
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
- Pros: Adapts to load, efficient memory usage
- Cons: Slight startup delay
- Best for: Variable load, shared servers
Ondemand PM:
pm = ondemand
pm.max_children = 50
pm.process_idle_timeout = 10s
- Pros: Minimal memory when idle
- Cons: Slow initial response
- Best for: Low traffic sites, development
2. Calculate pm.max_children
Formula:
pm.max_children = (Available RAM) / (Average PHP process size)
Example:
Available RAM: 2GB = 2048MB
PHP process: 50MB (check with: ps aux | grep php-fpm)
pm.max_children = 2048 / 50 = 40
Always leave headroom:
Recommended: 80% of calculated value
pm.max_children = 40 ร 0.8 = 32
3. Tune Dynamic PM Settings
Start Servers:
pm.start_servers = (min_spare + max_spare) / 2
Min/Max Spare:
pm.min_spare_servers = pm.max_children ร 0.1
pm.max_spare_servers = pm.max_children ร 0.2
Example for pm.max_children = 50:
pm.start_servers = 8
pm.min_spare_servers = 5
pm.max_spare_servers = 10
4. Enable Slow Request Logging
; Log slow requests
slowlog = /var/log/php-fpm/slow.log
request_slowlog_timeout = 5s
Monitor slow.log for bottlenecks:
sudo tail -f /var/log/php-fpm/slow.log
5. Set Request Limits
; Terminate long-running requests
request_terminate_timeout = 30s
; Restart workers after N requests (prevent memory leaks)
pm.max_requests = 500
6. Monitor Status Page Regularly
Set up alerts for:
listen_queue > 0
(backlog)max_children_reached > 0
(saturation)slow_requests
increasingidle_processes < 2
(no capacity)
PHP-FPM Performance Tuning
Optimize Process Manager
For high traffic:
pm = static
pm.max_children = 100
For variable traffic:
pm = dynamic
pm.max_children = 50
pm.min_spare_servers = 10
pm.max_spare_servers = 20
Optimize Request Handling
Disable access log (status endpoint):
location /status {
access_log off; # Reduce I/O
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
}
Enable OPcache:
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
Memory Optimization
Reduce memory_limit if possible:
memory_limit = 128M # Adjust based on needs
Monitor actual usage:
ps aux | grep php-fpm | awk '{sum+=$6} END {print sum/1024 " MB"}'
Advanced Configuration
Multiple PHP-FPM Pools
Monitor multiple pools:
plugins:
php_fpm_www:
enabled: true
status_url: http://127.0.0.1:8080/status?json
php_fpm_api:
enabled: true
status_url: http://127.0.0.1:8081/api-status?json
Configure different pools:
; /etc/php/8.1/fpm/pool.d/www.conf
[www]
pm.status_path = /status
; /etc/php/8.1/fpm/pool.d/api.conf
[api]
pm.status_path = /api-status
Unix Socket Monitoring
Direct socket access:
plugins:
php_fpm:
enabled: true
status_url: http://unix:/run/php/php8.1-fpm.sock:/status?json
Note: Requires HTTP client support for Unix sockets (not all clients support this).
Docker Container
Monitor PHP-FPM in Docker:
plugins:
php_fpm:
enabled: true
status_url: http://php-fpm:9000/status?json
Expose status via TCP:
; PHP-FPM config in Docker
listen = 0.0.0.0:9000
pm.status_path = /status
Example Configurations
Nginx + PHP-FPM Socket
plugins:
php_fpm:
enabled: true
status_url: http://127.0.0.1:8080/status?json
Nginx config:
server {
listen 127.0.0.1:8080;
location /status {
access_log off;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
allow 127.0.0.1;
deny all;
}
}
Apache + PHP-FPM
plugins:
php_fpm:
enabled: true
status_url: http://127.0.0.1:8080/fpm-status?json
Apache config:
<VirtualHost 127.0.0.1:8080>
<Location /fpm-status>
ProxyPass "unix:/run/php/php8.1-fpm.sock|fcgi://localhost/"
Require local
</Location>
</VirtualHost>
Multiple PHP Versions
plugins:
php74:
enabled: true
status_url: http://127.0.0.1:8074/status?json
php81:
enabled: true
status_url: http://127.0.0.1:8081/status?json
Limitations
Current Limitations
- No per-request details - Only pool-wide statistics
- No memory per process - Use full status for detailed metrics
- No OPcache metrics - Monitor separately via PHP script
Scalability
Tested with:
- Pools with 200+ processes
- Handling 10,000+ req/sec
- Multiple pools per server
Performance:
- Status endpoint response constant regardless of pool size
- No impact on PHP-FPM performance
Next Steps
- View all plugins
- Nginx Plugin - Often used together
- Apache Plugin - Alternative web server
- System Requirements
- Overview
- Requirements
- PHP-FPM Version
- PHP-FPM Configuration
- Python Dependencies
- Configuration
- Basic Configuration
- With Custom Socket
- HTTP via Nginx/Apache
- All Configuration Options
- Environment Variables
- PHP-FPM Setup
- Enable Status Page
- Nginx Configuration
- Apache Configuration
- Security Considerations
- Collected Metrics
- Dashboard Metrics
- Overview Card
- Process Pool Chart
- Queue Metrics Chart
- Request Rate Chart
- Process Limit Chart
- Installation
- Quick Install
- Install on Existing Agent
- Testing
- Manual Plugin Test
- Test Status Endpoint
- Test Ping Endpoint
- Troubleshooting
- Plugin Not Collecting Metrics
- Common Errors
- Performance Impact
- On PHP-FPM
- On Agent
- Use Cases
- 1. Process Pool Monitoring
- 2. Queue Saturation
- 3. Slow Request Detection
- 4. Capacity Planning
- Best Practices
- 1. Choose Correct Process Manager
- 2. Calculate pm.max_children
- 3. Tune Dynamic PM Settings
- 4. Enable Slow Request Logging
- 5. Set Request Limits
- 6. Monitor Status Page Regularly
- PHP-FPM Performance Tuning
- Optimize Process Manager
- Optimize Request Handling
- Memory Optimization
- Advanced Configuration
- Multiple PHP-FPM Pools
- Unix Socket Monitoring
- Docker Container
- Example Configurations
- Nginx + PHP-FPM Socket
- Apache + PHP-FPM
- Multiple PHP Versions
- Limitations
- Current Limitations
- Scalability
- Next Steps