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 listen does not match fastcgi_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.