In the past, PHP often ran as a module directly in the web server. Today, most installations separate the two: the web server handles connections, encryption, and static files, while PHP-FPM executes the PHP scripts. Communication uses the FastCGI protocol. The PHP manual describes FPM as a FastCGI implementation with features that are especially useful for heavily loaded websites.
How PHP-FPM works
A master process starts and monitors the worker processes. These are organized into pools. According to the PHP manual, each pool can run under its own user and group, listen on its own port or socket, and use its own php.ini values. This makes it possible to cleanly separate several websites on one server.
The web server forwards requests for PHP files to the appropriate pool, in nginx for example via the fastcgi_pass directive, in Apache via the mod_proxy_fcgi module. A free worker process executes the script and returns the response.
Further features according to the manual:
- graceful stopping and restarting of processes
- a "slowlog" that logs the PHP call stack for unusually slow requests
- a status page with output in JSON, XML, or OpenMetrics
- the function
fastcgi_finish_request(), which completes the response to the browser while the script continues working in the background
Process management
The pm setting determines how worker processes are created:
- static: a fixed number of processes, set with
pm.max_children - dynamic: a number of spare processes between a minimum and a maximum value
- ondemand: processes start only when needed and terminate after an idle period, by default after ten seconds
pm.max_children limits the number of requests processed concurrently and should match the available memory. With pm.max_requests, a process is restarted after a certain number of requests, which helps against memory leaks in libraries. request_terminate_timeout terminates requests that run too long.
Typical deployment scenarios
- nginx with PHP-FPM as the foundation for content management systems, shops, or frameworks such as Laravel
- a server with several websites, each in its own pool with its own user
- containers in which the web server and PHP-FPM run separately and are scaled
Security
- Socket instead of an open port: If the web server and PHP-FPM run on the same machine, the PHP manual recommends a Unix socket. The reason given in the manual: an openly reachable FastCGI endpoint allows arbitrary code execution.
- Secure TCP: If TCP is used, allow only the web servers' addresses with
listen.allowed_clientsand block the port with a firewall. Without this setting, PHP-FPM accepts connections from any address. - One pool per application: Run each website under its own user with minimal rights, following least privilege. A compromised application then cannot reach the files of the others.
- Limit executable extensions:
security.limit_extensionsis set to.php .pharby default and should not be extended, so that uploaded files of other types do not run as code. - Protect the status page: Make the status page reachable only internally or with authentication.
- Hide the version: Remove the
X-Powered-Byheader withexpose_php = Offor in the web server. The security header generator in the TOMORIS Toolbox generates the appropriate lines for nginx and Apache. - Stay up to date: PHP-FPM belongs to the respective PHP version and receives security updates with it, see PHP end of life.
Performance and operation
The number of processes results from the memory per process and the server's available memory. The status page and slowlog show whether requests are waiting or individual scripts are slowing things down. Together with OPcache, the pool configuration largely determines response times. Configuration changes require a reload of the service and should be made as planned changes.
How it differs
CGI starts a new process for every request, while FastCGI keeps processes permanently ready. PHP-FPM is PHP's process manager for FastCGI. The Apache module mod_php, by contrast, executes PHP directly in the web server process. The PHP command line (CLI) is independent of PHP-FPM and has its own settings.