最後更新: 2018-01-22
目錄
介紹
php5-fpm - PHP FastCGI Process Manager
* process spawning
systemd-+... |-php-fpm-+-php-fpm | |-php-fpm | |-php-fpm | |-php-fpm | |-php-fpm | `-php-fpm
Pool
不同的 Pool 是不同設定的 php process, 比如 php version, upload_max_filesize
Pool 是用不同的 port 去區分 (Default first pool: 9000/TCP)
Daemon
runs as a daemon and receives Fast/CGI requests.
Browser --> Nginx --> php-fpm --> php
* 當 Nginx 連不到 php-fpm proccess 時, 那 client 會收到 "502 Bad Gateway"
php5-fpm
Opts:
- -t Test FPM configuration file
- -i PHP information and configuration
- -m Show compiled in modules
php*-fpm 設定
php-fpm 主設定檔
/etc/php5/fpm/php-fpm.conf
; The maximum number of processes FPM will fork. ; The global number of processes when using dynamic PM within a lot of pools. process.max = 64 ; child processes to wait for a reaction on signals from master process_control_timeout = 0 ; Set open file descriptor rlimit for the master process rlimit_files = 10240 ; -19 (highest priority) to 20 (lower priority) process.priority = 1 # 每個 Pool 的獨立 Setting include=/etc/php5/fpm/pool.d/*.conf
Pool 的設定
/etc/php5/fpm/pool.d/www.conf
# 這是 pool 的名, variable $pool 相當於這字 [www] # 這 pool 的 proccess 的執行身分 user = www-data group = www-data # TCP listen = 127.0.0.1:9000 listen.allowed_clients = 127.0.0.1 # backlog: maximum length to which the queue of pending connections # man 2 listen 有解釋. Default: -1 => unlimited. 另見 listen.backlog = 128 # Socket listen = /var/run/php5-fpm.sock listen.owner = www-data listen.group = www-data listen.mode = 0660 # Proccess 數量設定 pm = dynamic # alive at the same time (ApacheMaxClients) # simultaneous requests that will be served. pm.max_children = 32 # children created on startu pm.start_servers = 4 # children in 'idle' pm.min_spare_servers = 2 pm.max_spare_servers = 6 # idle process will be killed pm.process_idle_timeout = 10s # each child process should execute before respawning pm.max_requests = 1024 # real-time FPM status monitoring # Default Value: not set # http://127.0.0.1/status Or http://www.foo.bar/status?full pm.status_path = /status # The access log file ; Default: not set ; Default Format: "%R - %u %t \"%m %r\" %s" ; %R: remote IP address ; %u: remote user ; %t: server time ; %m: request method ; %r: the request URI ; %s: status access.log = /var/log/fpm-php/pool/$pool.access.log ; The log file for slow requests slowlog = /var/log/fpm-php/pool/$pool.log.slow request_slowlog_timeout = 10 request_terminate_timeout = 10m # Limits the extensions of the main script FPM will allow to parse. security.limit_extensions = .php .php3 .php4 .php5 # Additional php.ini defines, specific to this pool of workers. php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f [email protected] php_flag[display_errors] = off php_admin_value[error_log] = /var/log/fpm-php/pool/$pool.log php_admin_flag[log_errors] = on php_admin_value[memory_limit] = 128M php_admin_value[max_execution_time] = 180 php_admin_value[date.timezone] = Asia/Hong_Kong php_admin_value[upload_max_filesize] = 15M php_admin_value[post_max_size] = 20M php_admin_value[short_open_tag] = on
# Restart Service
service php-fpm restart
nginx 與 php 的溝通時間
nginx
fastcgi_connect_timeout 300s; fastcgi_send_timeout 300s; fastcgi_read_timeout 300s;
php-fpm
php_admin_value[max_execution_time] = 300 php_admin_value[max_input_time] = 300 php_admin_value[default_socket_timeout] = 300
Data size
client_max_body_size 50M;
FPM Log
Default: /var/log/php-fpm.log
Setting: /etc/php-fpm.conf
; If it's set to "syslog", log is sent to syslogd instead of file error_log = /var/log/php-fpm/error.log log_level = notice
Or
;syslog.facility = daemon ;syslog.ident = php-fpm
Nginx FPM 設定
snippets/php56-fpm.conf
location ~* \.php$ {
# The "if" lets NGINX check whether the *.php does indeed exist
# to prevent NGINX to feeding PHP FPM non php script file
# (like uploaded image)
# 不能用 "try_files $uri =404;", 因為底有另一個 "if"
if (!-f $document_root$fastcgi_script_name) { return 404; }
#NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
# disallows the FPM to process files in the /uploads/ directory
if ($uri !~ "^/uploads/") {
# fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_pass php56-fpm;
}
}
snippets/common.conf
location ~ /\. { deny all; }
location = /favicon.ico { log_not_found off; access_log off; }
location = /robots.txt { log_not_found off; access_log off; }
# disallows access php in ? folder
location ~* /(?:uploads|files)/.*\.php$ { deny all; }
# no php is touched for static content, 因為中了 "$uri" 或 "$uri/"
location / { try_files $uri $uri/ /index.php?$args; }
sites-enabled/datahunter.org.conf
# vhost 設定 upstream php56-fpm { server 127.0.0.1:9056; } server { server_name datahunter.org www.datahunter.org; listen 80; root /home/vhosts/datahunter.org/public_html; index index.php index.html index.htm; ... # Protect admin panel location ~ ^/(wp-admin|wp-login\.php) { auth_basic "Restricted"; auth_basic_user_file htpasswd; } ... include snippets/common.conf; include snippets/php56-fpm.conf; }
Status page config in Nginx
Setting:
location ~ ^/(status|ping)$ { access_log off; allow 127.0.0.1; deny all; include fastcgi_params; fastcgi_pass 127.0.0.1:9000; }
查看 status
curl -k https://owncloud.datahunter.org:8443/status
pool: www
process manager: dynamic
start time: 03/May/2014:09:29:47 +0000 # started or reloaded
start since: 110
accepted conn: 12
listen queue: 0
max listen queue: 0
listen queue len: 128
idle processes: 3
active processes: 1
total processes: 4
max active processes: 1
max children reached: 0 # 多少次到達了 children limit
listen queue
The number of request in the queue of pending connections.
If this number is non-zero, then you better increase number of process FPM can spawn.
listen queue < listen queue len
listen queue len (listen.backlog)
the size of the socket queue of pending connections
total processes (idle + active)
The current total number of processes.
Since FPM has started
max listen queue
The maximum number of requests in the queue of pending connections
max active processes
The maximum number of active processes since FPM has started
max children reached
The number of times that pm.max_children has been reached
slow requests
The total number of requests that have hit the configured request_slowlog_timeout
Output Format (short/full)
# short status
- /status
- status?json
- /status?html
- /status?xml
# full status
- /status?full
- /status?json&full
- /status?html&full
- /status?xml&full
Status page on Apache
# RHEL
conf.d/php-fpm-status.conf
<LocationMatch "/status"> Require ip 127.0.0.1 # Require ip 1.2.3.4 # Your IP here # Adjust the path to the socket if needed #ProxyPass "unix:/run/php-fpm/www.sock|fcgi://localhost/status" ProxyPass "fcgi://localhost:9080/php-fpm-status" </LocationMatch> <LocationMatch "/ping"> Require ip 127.0.0.1 # Require ip 1.2.3.4 # Your IP here # Adjust the path to the socket if needed #ProxyPass "unix:/run/php-fpm/www.sock|fcgi://localhost/ping" ProxyPass "fcgi://localhost:9080/php-fpm-ping" </LocationMatch>
php-fpm.conf
ping.path = /php-fpm-ping pm.status_path = /php-fpm-status
Test
- curl localhost/php-fpm-ping
- curl localhost//php-fpm-status
fastcgi setting
fastcgi_intercept_errors
fastcgi_intercept_errors on; # Default: off
Determines whether FastCGI server responses with codes
greater than or equal to 300 should be passed to a client or
be intercepted and redirected to nginx for processing with the error_page directive.
fastcgi_split_path_info
Syntax: fastcgi_split_path_info regex;
The fastcgi_split_path_info regex capable to correctly handle request like
- /test.php/foo/blah.php
- /test.php/
first regex capture: becomes a value of the $fastcgi_script_name
second regex capture: becomes a value of the $fastcgi_path_info
i.e.
Setting
fastcgi_split_path_info ^(.+?\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info;
request "/show.php/article/0001"
$fastcgi_script_name = first = /show.php
$fastcgi_path_info = second = /article/0001
php.ini - cgi.fix_pathinfo
cgi.fix_pathinfo (Default: 1)
# 修改
sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g' /etc/php.ini
# Checking
test.php
<?php var_export($_SERVER)?>
* Pay attention to the value of
- REQUEST_URI,
- SCRIPT_FILENAME,
- SCRIPT_NAME,
- PATH_INFO, PHP_SELF
Request: /path/to/script.php/THIS/IS/PATH/INFO
[1]
PATH_INFO = /THIS/IS/PATH/INFO
SCRIPT_FILENAME = /path/to/script.php
[0]
make PHP_SELF variable broken (not equal to DOCUMENT_URI).
Remark
現在已很小要修改 cgi.fix_pathinfo 了, 因為 php 有 security.limit_extensions
security.limit_extensions 會限制了 php(process) 執行那些檔案
/etc/php-fpm.d/www.conf
# Default Value: .php security.limit_extensions = .php
.user.ini
要放在 public_html 才有效 !! (public_html/.user.ini)
由於它是放在 public_html 內, 所以要用 .htaccess 保護它 (public_html/.htaccess)
<Files ".user.ini"> Require all denied </Files>
.user.ini
short_open_tag=On memory_limit=256M upload_max_filesize=50M post_max_size=60M date.timezone=Asia/Hong_Kong session.gc_maxlifetime=3600 max_execution_time=60 error_reporting=E_ALL & ~E_WARNING & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE
Notes: 不支援的 Settings
- expose_php=Off
有關 .user.ini 的 php.ini Settings
user_ini.cache_ttl 300 user_ini.filename .user.ini