php runtime and server environment
FPM Pools
PHP-FPM runs PHP code for web servers such as Nginx, Caddy, and Apache with FastCGI. An FPM pool is a group of PHP worker processes with its own listener, user, process settings, logs, and optional status endpoint.
Pools matter because they decide who PHP runs as, how many requests can be processed at the same time, where slow requests are logged, and how the web server reaches PHP.
A pool configuration
A small pool configuration can look like this:
[www]
user = www-data
group = www-data
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 8
pm.status_path = /fpm-status
slowlog = /var/log/php8.3-fpm/www-slow.log
request_slowlog_timeout = 5s
The pool name is [www]. Large servers may have separate pools for separate sites or applications so each can run as a different user and have different limits.
Pool users and permissions
user and group decide which operating-system account executes PHP code. This account needs access to application files, cache directories, upload directories, log directories, and any Unix socket it must use.
Do not run application pools as root. A compromised PHP application should not have full server privileges. Production setups often use a dedicated user per site or service.
Process manager modes
The pm setting controls how PHP-FPM manages worker processes.
static starts exactly pm.max_children workers and keeps them running. It is predictable but can waste memory on low-traffic sites.
pm = static
pm.max_children = 10
dynamic keeps a range of spare workers and grows under load. It is common for general web applications.
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 8
ondemand starts workers only when requests arrive and stops idle workers later. It saves memory but can add startup latency.
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s
Capacity and memory
pm.max_children is a capacity limit. If it is too low, requests queue and users wait. If it is too high, the server can run out of memory.
A rough review is:
safe max children = available memory for PHP / average memory per PHP request
If the server has about 1024M available for PHP and each request uses about 64M, a safe starting point may be around 16 children, with room left for the web server, database client buffers, OPcache, and the operating system.
This is not a perfect formula. Real tuning needs metrics, traffic patterns, slow request data, and memory observations.
Status page
The FPM status page reports pool activity. It can show active processes, idle processes, accepted connections, queue length, and whether the pool has reached pm.max_children.
pm.status_path = /fpm-status
Do not expose this publicly. Restrict it by IP, internal network, authentication, or a protected monitoring path. It can reveal operational details about the application.
Slowlog
The slowlog records stack traces for PHP requests that run longer than a configured threshold.
slowlog = /var/log/php8.3-fpm/www-slow.log
request_slowlog_timeout = 5s
This helps separate "the server is slow" from "this request is spending time in one specific function, query, API call, or filesystem operation". Slowlog is especially useful when a request eventually succeeds but takes too long.
Common problems
- The web server cannot connect to PHP-FPM because
listendoes not matchfastcgi_pass. - The socket exists but the web server user cannot access it.
- Uploads, sessions, cache, or logs fail because the pool user cannot write to a directory.
- Traffic spikes hit
pm.max_children, causing queued requests and timeouts. - The status page is exposed to the public internet.
- Slowlog is not configured, so performance debugging starts with guessing.
What you should be able to do
After this lesson, you should be able to read a PHP-FPM pool file, explain the pool user, identify the listener, understand the process manager mode, use status and slowlog safely, and spot capacity or permission issues before blaming application code.
Practice
Task: Review An FPM Pool
Write a short review of a PHP-FPM pool for a small production application.
Requirements
- Include the pool user and explain why it should not be
root. - Include a Unix socket listener with matching owner, group, and mode.
- Choose a process manager mode and justify it.
- Include a safe status page note.
- Include slowlog settings and explain what problem they help debug.
Check your work
The review should read like something useful during a deployment or incident review, not a list of copied directives.
Show solution
[shop]
user = shop
group = shop
listen = /run/php/shop.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 16
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.status_path = /internal/fpm-status
slowlog = /var/log/php-fpm/shop-slow.log
request_slowlog_timeout = 5s
Review points:
The pool runs as the shop user, not root, so a compromised application has limited operating-system permissions.
The socket is owned by www-data, which matches the expected web server user. Mode 0660 means the socket is not world-accessible.
dynamic is a sensible starting point for a small web application because it keeps spare workers ready but does not require every possible worker to stay alive all the time.
The status path must be restricted by the web server to internal monitoring or trusted IPs only.
The slowlog will help identify long-running PHP requests by recording where the request was spending time after 5 seconds.
This review checks how requests enter the pool, which user executes PHP, how capacity is controlled, and whether debugging tools exist before an incident happens.