Nginx and PHP-FPM
Prerequisites
- Installation of Nginx
- Installation of PHP-FPM
- Basic configuration of Nginx
- Basic configuration of PHP-FPM
Basic configuration in Nginx
Using upstream to define our PHP-FPM socket
Within the http context we need to define an upstream server for our PHP-FPM socket. Specifying the server in an upstream block allows us to reference the socket at a single location.
upstream php-fpm {
server unix:/var/run/php-fpm.sock;
}
Creating a location context to handle PHP requests
Within the your server block nested inside the http context we set up location context to handle PHP objects.
A location context simply sets the configuration based on the request URI.
Example location context
# Note the php-fpm is set to a UNIX socket,
# please ensure your php-fpm is set to listen here
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
Test and reload Nginx configuration
nginx -t
service nginx reload
Configuring PHP-FPM
In the default php-fpm.conf configuration file, the pools are often included from the /etc/php-fpm.d/ directory as a part of the first directive. As the PHP FPM definitions have been covered in PHP-FPM : Part 2 – Basic Setup we will not be duplicating them here.
Example php-fpm.conf
;;;;;;;;;;;;;;;;;;;;;
FPM Configuration ;
;;;;;;;;;;;;;;;;;;;;;
; All relative paths in this configuration file are relative to PHP’s install
; prefix.
; Include one or more files. If glob(3) exists, it is used to include a bunch of
; files from a glob(3) pattern. This directive can be used everywhere in the
; file.
include=/etc/php-fpm.d/*.conf
;;;;;;;;;;;;;;;;;;
; Global Options ;
;;;;;;;;;;;;;;;;;;
[global]
; Pid file
; Default Value: none
pid = /var/run/php-fpm/php-fpm.pid
; Error log file
; Default Value: /var/log/php-fpm.log
error_log = /var/log/php-fpm/error.log
; Log level
; Possible Values: alert, error, warning, notice, debug
; Default Value: notice
;log_level = notice
; If this number of child processes exit with SIGSEGV or SIGBUS within the time
; interval set by emergency_restart_interval then FPM will restart. A value
; of ‘0’ means ‘Off’.
; Default Value: 0
;emergency_restart_threshold = 0
; Interval of time used by emergency_restart_interval to determine when
; a graceful restart will be initiated. This can be useful to work around
; accidental corruptions in an accelerator’s shared memory.
; Available Units: s(econds), m(inutes), h(ours), or d(ays)
; Default Unit: seconds
; Default Value: 0
;emergency_restart_interval = 0
; Time limit for child processes to wait for a reaction on signals from master.
; Available units: s(econds), m(inutes), h(ours), or d(ays)
; Default Unit: seconds
; Default Value: 0
;process_control_timeout = 0
; Send FPM to background. Set to ‘no’ to keep FPM in foreground for debugging.
; Default Value: yes
daemonize = yes
Example pool.conf
; Start a new pool named ‘www’.
[www]
; The address on which to accept FastCGI requests.
; Valid syntaxes are:
; ‘ip.add.re.ss:port’ – to listen on a TCP socket to a specific address on
; a specific port;
; ‘port’ – to listen on a TCP socket to all addresses on a
; specific port;
; ‘/path/to/unix/socket’ – to listen on a unix socket.
; Note: This value is mandatory.
listen = /var/run/php-fpm.sock;
; Set listen(2) backlog. A value of ‘-1’ means unlimited.
; Default Value: -1
; listen.backlog = -1
; List of ipv4 addresses of FastCGI clients which are allowed to connect.
; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original
; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address
; must be separated by a comma. If this value is left blank, connections will be
; accepted from any ip address.
; Default Value: any
; listen.allowed_clients = 127.0.0.1
; Set permissions for unix socket, if one is used. In Linux, read/write
; permissions must be set in order to allow connections from a web server. Many
; BSD-derived systems allow connections regardless of permissions.
; Default Values: user and group are set as the running user
; mode is set to 0660
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user’s group
; will be used.
; RPM: apache Choosed to be able to access some dir as httpd
user = nginx
; RPM: Keep a group allowed to write in log dir.
group = nginx
; Choose how the process manager will control the number of child processes.
; Possible Values:
; static – a fixed number (pm.max_children) of child processes;
; dynamic – the number of child processes are set dynamically based on the
; following directives:
; pm.max_children – the maximum number of children that can
; be alive at the same time.
; pm.start_servers – the number of children created on startup.
; pm.min_spare_servers – the minimum number of children in ‘idle’
; state (waiting to process). If the number
; of ‘idle’ processes is less than this
; number then some children will be created.
; pm.max_spare_servers – the maximum number of children in ‘idle’
; state (waiting to process). If the number
; of ‘idle’ processes is greater than this
; number then some children will be killed.
; Note: This value is mandatory.
pm = dynamic
; Choose how the process manager will control the number of child processes.
; Possible Values:
; static – a fixed number (pm.max_children) of child processes;
; dynamic – the number of child processes are set dynamically based on the
; following directives:
; pm.max_children – the maximum number of children that can
; be alive at the same time.
; pm.start_servers – the number of children created on startup.
; pm.min_spare_servers – the minimum number of children in ‘idle’
; state (waiting to process). If the number
; of ‘idle’ processes is less than this
; number then some children will be created.
; pm.max_spare_servers – the maximum number of children in ‘idle’
; state (waiting to process). If the number
; of ‘idle’ processes is greater than this
; number then some children will be killed.
; Note: This value is mandatory.
pm = dynamic
; The number of child processes to be created when pm is set to ‘static’ and the
; maximum number of child processes to be created when pm is set to ‘dynamic’.
; This value sets the limit on the number of simultaneous requests that will be
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
; CGI.
; Note: Used when pm is set to either ‘static’ or ‘dynamic’
; Note: This value is mandatory.
pm.max_children = 50
; The number of child processes created on startup.
; Note: Used only when pm is set to ‘dynamic’
; Default Value: min_spare_servers + (max_spare_servers – min_spare_servers) / 2
pm.start_servers = 5
; The desired minimum number of idle server processes.
; Note: Used only when pm is set to ‘dynamic’
; Note: Mandatory when pm is set to ‘dynamic’
pm.min_spare_servers = 5
; The number of requests each child process should execute before respawning.
; This can be useful to work around memory leaks in 3rd party libraries. For
; endless request processing specify ‘0’. Equivalent to PHP_FCGI_MAX_REQUESTS.
; Default Value: 0
;pm.max_requests = 500
; The log file for slow requests
; Default Value: not set
; Note: slowlog is mandatory if request_slowlog_timeout is set
slowlog = /var/log/php-fpm/www-slow.log
; Additional php.ini defines, specific to this pool of workers. These settings
; overwrite the values previously defined in the php.ini. The directives are the
; same as the PHP SAPI:
; php_value/php_flag – you can set classic ini defines which can
; be overwritten from PHP call ‘ini_set’.
; php_admin_value/php_admin_flag – these directives won’t be overwritten by
; PHP call ‘ini_set’
; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.
; Defining ‘extension’ will load the corresponding shared extension from
; extension_dir. Defining ‘disable_functions’ or ‘disable_classes’ will not
; overwrite previously defined php.ini values, but will append the new value
; instead.
; Default Value: nothing is defined by default except the values in php.ini and
; specified at startup with the -d argument
;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
;php_flag[display_errors] = off
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
;php_admin_value[memory_limit] = 128M
; Set session path to a directory owned by process user
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/session
Simple definitions
Within the pool there are a few definitions we need to modify for a standard configuration:
Loading configuration changes into PHP-FPM
Prior to reloading the service we need to test and verify our configurations for PHP-FPM are without syntax errors. Once the configuration file has been verified we can then reload the service without issue.
php-fpm -tt
service php-fpm reload
Multiple Pools
PHP-FPM Pools are isolated PHP environments. They allow different configuration and some protection between different web applications running on the same server. It also allows for different UID/GIDs for running scripts. This helps create a much more secure (and easier to maintain) PHP setup for multiple sites, where the PHP scripts do not need to have full ‘apache’ (or ‘www-data’) permissions across the filesystem.
Filesystem Layout for Sites
To ensure consistency, a common filesystem layout should be used for all sites with php-fpm. A good recommendation is
/var/www/vhosts/example.com/ – owned by root.examplecom, mode 0751, sftp user chrooted to this folder
/var/www/vhosts/example.com/public/ – owned by examplecom.examplecom, mode 0755
/var/www/vhosts/example.com/run/ – owned by root.root, mode 0755
/var/www/vhosts/example.com/log/ – owned by root.root, mode 0755
/var/www/vhosts/example.com/uploads/ – owned by examplecom.examplecom, mode 0755
Import Directives for Additional Pool Configuration
For multiple pools, some common values will need to be updated. Here is an example of what should be set in a multi-pool enviroment that need placing in the pool.conf file.
[examplecom]
prefix = /var/www/vhosts/example.com/ ; This is the pool home, relative paths in the configuration are based
on this directory
listen = run/php5-fpm.sock ; This is relative path.to the prefix, nginx should have a fastcgi_pass unix:
prefix/listen
user = examplecom ; [Optional] User associated with pool. (Affects write operations)
group = examplecom ; [Optional] Group associated with pool. (Affects write operations)
Nginx Changes
Once the pools are configured, nginx needs updating.
Create a new upstream definition
upstream php-fpm-examplecom-sock {
server unix:/var/www/vhosts/example.com/run/php5-fpm.sock;
}
and assign it to fastcgi_pass.
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php-fpm-examplecom-sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
Selective Pools
An advanced use case for multiple pools is multiple pools for the same domain. The primary use case for this is load balanced servers with lsyncd. Since updates should only happen on the master server, a Read-Only pool is used for handling the request locally and a Read-Write pool is used to direct the request to the master.
This require 2 upstream definitions one for master and one for local. Master must be a TCP socket and not a Unix socket.
# Local R/O socket
upstream ro_php_fpm { server unix:/var/run/php5-fpm.sock; }
# Master R/W socket
upstream rw_php_fpm { server master:9000; }
Next, we have to define what is R/O and what is R/W. This varies from application to application. Included are two common configurations WordPress and Magento.
Nginx Definitions
map Maps input parameters to a specific output string
Magento
map “METHOD:$request_method COOKIE:<${cookie_adminhtml}> URL:$request_uri.” $fcgi_pass {
default ro_php_fpm;
~METHOD:POST rw_php_fpm;
~METHOD:PUT rw_php_fpm;
~URL:.*admin.* rw_php_fpm;
~URL:/var/export/ rw_php_fpm;
~URL:/install/ rw_php_fpm;
~URL:/contacts/ rw_php_fpm;
~URL:^media/captcha/.* rw_php_fpm;
~COOKIE:<> ro_php_fpm;
# ~COOKIE:<.+> rw_php_fpm; # Custom cookies can be added with regex
}
WordPress
map “METHOD:$request_method URL:$request_uri.” $fcgi_pass {
default ro_php_fpm;
~URL:.*admin-ajax.* ro_php_fpm;
~METHOD:POST rw_php_fpm;
~METHOD:PUT rw_php_fpm;
~URL:.*admin.* rw_php_fpm;
}
To use these directives set fastcgi_pass directive to $fcgi_pass .
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass $fcgi_pass;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}