PHP-FPM

The PHP FastCGI Process Manager (PHP-FPM) is an implementation of the FastCGI specification.


Installation

php-fpm(8) naturally depends on php(1). See here for help with installation, and here for help with configuration.

Most Linux and BSD distributions will offer a php-fpm package.

Official container images are available from the upstream development team. They are tagged like php:<version>-fpm


Configuration

php-fpm(8) listens on one or more ports or sockets. Each point of contact is a pool.

Each pool should have it's own configuration file under /etc/php/php.fpm.d. A pool's name ($pool) is derived from the section header.

As an example:

[www]
user = www-data
group = www-data

listen = 9000
listen.allowed_clients = 127.0.0.1, 192.168.86.1

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

TCP Sockets

The above example uses a shorthand: listen = 9000. This causes php-fpm(8) to listen on all addresses at port 9000.

However, listen.allowed_clients overrides this with a client whitelist. This should be comma-separated.

An IPv4 address is specified like 127.0.0.1:9000; an IPv6 address is specified like [::1]:9000.

Unix Sockets

To use a Unix socket to pass requests, try:

listen = /run/php-fpm/php-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Static Process Management

A pool spawns and maintains pm.max_children number of processes.

pm = static
pm.max_children = 5

Dynamic Process Management

A pool spawns pm.start_servers processes. At any given time, some number are 'idle'. The pool tries to keep this number within the range of pm.min_spare_servers to pm.max_spare_servers, never surpassing pm.max_children.

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

On-Demand Process Management

A pool spawns processes on-demand up until pm.max_children. A process is killed after pm.process_idle_timeout has passed.

pm = ondemand
pm.max_children = 5
pm.process_idle_timeout = 10s

Process Termination

php(1) scripts are known to leak memory frequently. As such, a regular task is to terminate long-running processes.

A simple solution is to set pm.max_requests to any number other than 0. Processes are killed after handling this number of requests.

Hardening

As a security measure, the allowable script extensions should be set as strictly as possible.

security.limit_extensions = .php .html .htm

A pool can be hardened by isolating it to a distinct working directory, or even a chroot.

chroot = /absolute/path/to/chroot
# or
chdir = relative/or/absolute/path/to/working/directory

By default, php-fpm(8) clears all environment variables. This can be disabled, but a better strategy is to set specific environment variables.

env[HOSTNAME] = $HOSTNAME
env[TMP] = /tmp

The same is true of PHP system variables.

php_admin_value[error_log] = /var/log/php-fpm.log


Usage

Nginx

See here for details.

Apache

See here for details.

Containers

When containerizing a php(1) service, the web server should be kept separate. See other articles for help in configuring the web server containers.

A template container image recipe looks like:

FROM php:fpm-alpine
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY myapp/ /myapp/
COPY confs/ /usr/local/etc/php-fpm.d/
EXPOSE 9000
WORKDIR /myapp
CMD php-fpm --nodaemonize

By default, php-fpm(8) will not run as root. The --allow-to-run-as-root flag may need to be added.


See also

php-fpm(8)


CategoryRicottone

PHP/FPM (last edited 2023-05-25 17:00:50 by DominicRicottone)