Size: 4139
Comment:
|
Size: 3634
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
= FastCGI = | = PHP-FPM = |
Line 3: | Line 3: |
'''FastCGI''' is a PHP implementation of the Common Gateway Interface (CGI). It works especially well with [[NGINXSetup|NGINX]]. | The PHP '''FastCGI Process Manager''' ('''PHP-FPM''') is an implementation of the [[Protocols/CGI|FastCGI]] specification. <<TableOfContents>> |
Line 9: | Line 11: |
== Setup Directory == | == Installation == |
Line 11: | Line 13: |
The recommendation is to either serve web content from: | PHP-FPM naturally depends on `php(1)`. See [[PHP#Installation|here]] for help with installation, and [[PHP/Configuration|here]] for help with configuration. |
Line 13: | Line 15: |
* a dedicated top-level directory (such as `/srv`) that can be ''easily'' separately-mounted with special settings (i.e. `ro`--the read-only fstab option) * the traditional web content directory, `/var/www` |
Most Linux and BSD distributions will offer a `php-fpm` package. |
Line 16: | Line 17: |
Note that any directory can be a mounted device, but there are additional considerations. Many package managers expect standard directories to be writable. | Official container images are available from the upstream development team. They are tagged like `php:<version>-fpm` ---- |
Line 20: | Line 23: |
=== Setup Test Script === | == Configuration == |
Line 22: | Line 25: |
Write the below to `cgi/test.php`, under whichever directory structure you prefer. | `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: |
Line 25: | Line 32: |
<?php phpinfo(); ?> | [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 [[Linux/UnixSocket|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 = static 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 |
Line 32: | Line 149: |
== Setup User == Linux permissions and restrictions are most easily done through users, groups, and umasks. The recommendation is to set a specific user and group for the web service. The common options are `www-data` (Apache) and `http` (PHP). Depending on your ditro, these users and groups may already be created. See details on running `useradd` and `groupadd` in UserSetup. The directory and files setup above should be owned by this user. ---- == Setup Software == At a minimum, we need: php, php-fpm, fcgi, fcgiwrap, and nginx. Common additional tools include: * apache2-utils (a.k.a. apache-tools, httpd-utils, etc.) for creating .htpasswd files for basic restrictions === PHP === The primary configuration for PHP is found in `/etc/php/php.ini`. Some distributions carry two versions: * `php.ini-production` which is more secure * `php.ini-development` which is more backwards-compatible, and includes sensitive details in debugging messages Chuck the latter straight into the bin. Some key directives to check: {{{ ; Block calls from crafted URLs (i.e., `example.com/something-malicious.php`) cgi.force_redirect = On ; Disable access to filesystem file_uploads = Off ; Disable remote data retrieval allow_url_fopen = Off allow_url_include = Off }}} === PHP-FPM === PHP-FPM is configured by a system configuration (`/etc/php/php-fpm.conf`) and by pool configurations (`/etc/php/php-fpm.d/*.conf`). For the most part, the system configuration works out of the box. {{{ ; Pid file pid = /run/php-fpm/php-fpm.pid ; Error log error_log = /var/log/php-fpm.log }}} The pool configuration will need to be adjusted according to the user that was setup above. {{{ ; User/group of processes user = www-data group = www-data ; Socket file listen = /run/php-fpm/php-fpm.pid ; User/group of sockets listen.owner = www-data listen.group = www-data ; Restrictions on file extensions security.limit_extensions = .cgi .php ; Access log access.log = /var/log/php-fpm/access.log }}} === FastCGI and FCGIWrap === FastCGI takes a large number of parameters within NGINX configurations, so it is commonly 'configured' with `/etc/nginx/fastcgi_params`. This file should be created by default and should work by default. FCGIWrap is, as the name implies, a wrapper around FastCGI. It will work without configuration. |
== Usage == |
Line 125: | Line 155: |
For more details on NGINX configuration, see [[NGINXSetup|this walkthrough]]. A basic configuration for FastCGI would be: {{{ user www-data www-data; http { include mime.types; default_type application/mime.types; sendfile on; keepalive_timeout 65; gzip on; server { listen 80; server_name example.com; access_log /var/log/nginx/example.com/access.log; error_log /var/log/nginx/example.com/error.log; root /var/www; try_files $uri @cgi; location @cgi { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $realpath_root/my-cgi-script.cgi; fastcgi_param PATH_INFO $uri; fastcgi_param QUERY_STRING $args; fastcgi_param HTTP_HOST $server_name; fastcgi_pass unix:/run/fcgiwrap.sock; } } } }}} |
See [[NGINX/FastCGI#PHP_FPM|here]] for details. |
Line 160: | Line 159: |
---- | === Apache === |
Line 162: | Line 161: |
== Startup == ---- == Maintenance == |
See [[Apache/FastCGI#PHP_FPM|here]] for details. |
PHP-FPM
The PHP FastCGI Process Manager (PHP-FPM) is an implementation of the FastCGI specification.
Contents
Installation
PHP-FPM 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 = static 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.