Php-fpm

From wiki.mikejung.biz
Jump to: navigation, search

Liquidweb 728x90.jpg

PHP-FPM Overview

http://php-fpm.org/

PHP-FPM (FastCGI Process Manager) is fast. If you have a busy site and want to be able to handle lots of requests then you should at least test out PHP-FPM's performance.

Shared Hosting Security Issue with PHP-FPM and OPcache

If you plan on using PHP-FPM with PHP 5.5+'s built in opcache, please read the blog post below before you actually do that. Turns out that the opcode cache can be read by any user on the server. This means that if there are say, 10 seperate users, with their own vhosts and directories, and you configure one PHP-FPM pool per user, each user can still see what scripts are cached and their locations. Since they have read access to the cache they could potentially view all this data.

This is obviously a massive security concern, and even if no one exploits this, there is still a chance of scripts being read by the wrong user when generating a page, so websites could possibly be displaying the wrong data / info if there are multiple index.php scripts in the cache.

I can confirm that this is NOT an issue with FCGI and OPcache, only with PHP-FPM and OPcache

PHP-FPM Configuration Options

PHP-FPM Basic directives

  • pm = dynamic: Changes how PHP-FPM wil spin up PHP workers. The default setting uses the other settings to determine how to act. If you want a fixed number of PHP processes running, you can set this to static, if you only want to create new PHP-FPM processes when requested, use "ondemand", personally I like to use "dynamic" and set the lower limit for spare processes to 2 or 3 so that I always have PHP processes up and ready to handle connections.
  • pm.max_children = 10: Sets a maximum of 10 PHP-FPM Processes that are allowed to run at the same time. 10 pm.max_children should be a good place to start for most sites. Keep in mind that while this seems low, the average amount of time it takes for a PHP request to complete is somewhere in the 100ms to 200ms range, meaning that if you set this to 1 max children your site could theoretically handle around 5 - 10 requests/s which is a pretty decent amount of traffic if you have that many active connections 24/7.
  • pm.start_servers = 4: Sets how many PHP workers are activated when PHP-FPM starts up. Having more start servers for PHP-FPM will help to keep response times low when your site gets a sudden burst of traffic. If you configure PHP-FPM to only have 1 pm.start_servers and all of a sudden 5 people visit your site, your server will need to quickly spawn a few more processes, which can increase website load time slightly. This isn't a huge deal, but if you want to keep response times as low as possible make sure you set the start servers to something like 4 or 5 and make sure you configure the min and max spare servers for PHP-FPM to allow for whatever startserver value you pick.
  • pm.min_spare_servers = 4: Sets the minimum number of idle process that PHP-FPM will allow to live. If you start PHP-FPM with 4 processes, and want at least 4 PHP-FPM processes all the time then setting this to 4 is a safe bet, if you want to start with 4 processes, but allow for up to 5 idle processes, set this value to 5.
  • pm.max_spare_servers= 6: Sets the maximum number of idle processes PHP-FPM will allow to remain alive. If you want to be aggressive in terms of limiting the amount of RAM and CPU that PHP-FPM can use then you will want to configure pm.max_spare_servers to the same as, or slightly higher than pm.start_servers. You cannot set this value to be lower than the min spare servers, or start servers, otherwise PHP-FPM will not start. I would advise setting this value slightly higher than pm.start_servers

Memcached and PHP Unix Socket configuration for performance

Source: http://arstechnica.com/information-technology/2012/12/web-served-part-3-bolting-on-php-with-php-fpm/

If Memcached is installed, storing PHP session files in RAM can be much more efficient than storing on disk and can also save some IO. To configure this, you should modify the main php.ini file and change session.save_handler to memcached.

php -i | grep php.ini
vim /$path/to/php.ini
session.save_handler = memcache
session.save_path = unix:/tmp/memcached.sock

To change PHP-FPM's listening port to a Unix socket modify the main php-fpm pool's configuration file.

vim /etc/php5/fpm/pool.d/www.conf
##Change##
listen = 127.0.0.1:9000

##To##

listen = /var/run/php5-fpm.soc
listen.owner = www-data
listen.group = www-data

/etc/memcached.conf

# Default connection port is 11211
# -p 11211
# Specify which IP address to listen on.
# -l 127.0.0.1
# Listen on a Unix socket
-s /tmp/memcached.sock
-a 666

If Nginx is in use:

vim /etc/nginx/conf.d/php-sock.conf

upstream php5-fpm-sock {
    server unix:/var/run/php5-fpm.soc;
}

http://php.net/manual/en/install.fpm.configuration.php

FPM uses php.ini syntax for its configuration file - php-fpm.conf, and pool configuration files. This means that you need to make sure you update both files if you want to enable a new module, or update settings. If you only update the global php.ini file but do not update php-fpm then you more than likely will not be able to use the module or take advantage of new settings.

How to install Apache 2.4 Event and PHP-FPM on Ubuntu 14.10

Install Packages for Apache 2.4, MySQL, PHP and PHP-FPM

apt-get install apache2 mysql-server php5-mysql php5-fpm php5-gd php5-cli

Use this command to view the loaded modules for [Apache].

apache2ctl -M

Modify PHP-FPM's conf file and make sure its listening on tcp (localhost)

vim /etc/php5/fpm/pool.d/www.conf

;listen = /var/run/php5-fpm.sock
listen = 127.0.0.1:9000

Enable proxy_fcgi which also enables proxy. Restart Apache after these are enabled.

a2enmod proxy_fcgi

Enabling module proxy.
Enabling module proxy_fcgi.

service apache2 restart

Now you will want to edit your vhost(s) to pass PHP to FPM. I'm using 000-default since I have no other vhosts on the server, if you already have vhosts then edit them to include the ProxyPassMatch line shown below.

vim /etc/apache2/sites-enabled/000-default.conf

##Add this below CustomLog Line

ProxyPassMatch ^/(.*.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/$1

You should be able to restart both Apache and php5-fpm and have a working server!

service apache2 restart
service php5-fpm restart

To test that apache and php are working correctly, create phpinfo file and load it via browser.

vim /var/www/html/info.php


<?php

// Show all information, defaults to INFO_ALL
phpinfo();

?>

How to manually install and configure PHP-FPM on cPanel server

Please read this security warning section before you do this on a production server.

Create cpanel rawopts files for Apache and PHP

Create a rawopts file for php, when you run EasyApache these flags will be added when configuring PHP, since PHP-FPM is included in PHP 5.3+ you can enable PHP-FPM rather easily.

vim /var/cpanel/easy/apache/rawopts/all_php5

##Add these two lines

--enable-fastcgi
--enable-fpm

Create another rawopts file for apache with a single line.

vim /var/cpanel/easy/apache/rawopts/Apache2_4

##Add this line

--enable-proxy-fcgi=static

Run Easy Apache

Go ahead and run EA now that we have the two rawopts files in place.

/scripts/easyapache

Once EA is done you can run this command to make sure fpm and fastcgi are enabled.

php-config --configure-options

There should now be a php-fpm binary, use which to make sure it's there.

which php-fpm

/usr/local/sbin/php-fpm

Create PHP-FPM Configuration Files and Directories

Copy over cPanel's template to /etc/init.d

cp /home/cpeasyapache/src/php-5.5.20/sapi/fpm/init.d.php-fpm.in /etc/init.d/php-fpm
chmod a+x /etc/init.d/php-fpm
chkconfig php-fpm on

Now we need to edit this file and replace a few sections at the top

vim /etc/init.d/php-fpm

###REPLACE###
[email protected]@
[email protected]_prefix@
[email protected]@/php-fpm
[email protected]@/php-fpm.conf
[email protected]@/run/php-fpm.pid


###WITH###
prefix=/usr/local
exec_prefix=${prefix}
php_fpm_BIN=${exec_prefix}/sbin/php-fpm
php_fpm_CONF=${prefix}/etc/php-fpm.conf
php_fpm_PID=/var/run/php-fpm/php-fpm.pid
mkdir /var/run/php-fpm
mkdir /usr/local/etc/php-fpm.pool.d

Create global php-fpm.conf

Create the global php-fpm.conf file, I've removed any commented out lines to make the config file easier to look at. This is the global / default configuration for PHP-FPM, we will be adding per user configs in the next step

vim /usr/local/etc/php-fpm.conf


;;;;;;;;;;;;;;;;;;
; Global Options ;
;;;;;;;;;;;;;;;;;;

[global]
pid = /var/run/php-fpm/php-fpm.pid
error_log = /var/log/php-fpm.log
process.max = 20

;;;;;;;;;;;;;;;;;;;;
; Pool Definitions ; 
;;;;;;;;;;;;;;;;;;;;
[nobody]
user = nobody
group = nobody
listen = 127.0.0.1:9000
pm = ondemand
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
include=/usr/local/etc/php-fpm.pool.d/*.conf


Create cPanel User php-fpm.conf

This file is an example of how to configure each cPanel user to have their own pool / settings. There are ways to automate all of this, but I am doing this manually so it's easier to understand what is going on. Replace $cpanel_user with the actual cpanel user name.

vim /usr/local/etc/php-fpm.pool.d/$cpanel_user.conf


;;;;;;;;;;;;;;;;;;;;
; Pool Definition ; 
;;;;;;;;;;;;;;;;;;;;
[$CPANELUSER]
user = $CPANELUSER
group = $CPANELUSER

listen = /var/run/php-fpm/CPANELUSER.sock
listen.mode = 0666
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s
pm.max_requests = 256

Modify cPanel User vhost to use PHP-FPM

You can either enable all vhosts to use PHP-FPM, or you can just enable certain vhosts to use PHP-FPM, for this example I am just enabling PHP-FPM for a single account.

vim /usr/local/apache/conf/httpd.conf

##Find the vhost that you want to use PHP-FPM with, add this block inside the vhost. 

<IfModule mod_proxy_fcgi.c>
ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/var/run/php-fpm/$cpanel_user.sock|fcgi://localhost/home/$cpanel_user/public_html
</IfModule>

Start up PHP-FPM, then restart apache

service php-fpm start
service httpd restart

How to Enable PHP-FPM Access Logging

By default, the access log for PHP-FPM is not enabled. The error log is enabled and located at /var/log/php-fpm.log so if you do enable the access log I suggest setting a location that is in /var/log to make it easier to view both files.

These instructions assume that you are using a cPanel server and have used the cphstack script to get PHP-FPM installed and running. If you are not using cPanel then you should be able to modify the pool conf file located under /usr/local/etc/php-fpm.pool.d/

vim /opt/xstack/cphstack/php-fpm.pool.d/$domain1.com.conf

About half way down the file you should see a few lines that are commented out. You need to remove the ";" before the two lines below. You can name the access.log whatever you want, in my case I named it php-fpm.access.log. You can also modify the default PHP-FPM log formatting to include some useful metrics like process size in MB and the response time per request.

access.log = /var/log/php-fpm.access.log
access.format ="%t "%{megabytes}M MB %{seconds}d seconds" \"%m %f\" %s"

Note that I added "MB" and "seconds" to the format line so that you can tell what the values are later on when you look at the logs. If you don't label the columns then you would just see a "5" instead of "5 MB", or "0.100" instead of "0.100 seconds"

Save the configuration file, then restart PHP-FPM

service php-fpm restart

At this point you should be able to tail the access log and load a page and see new logs come in.

tail -f /var/log/php-fpm.access.log

Below is an example of what the PHP-FPM access log looks like once you've enabled and customized the output.

17/Mar/2015:13:10:37 -0400 5 MB 0.164 seconds "GET /home/$user/public_html/wiki//index.php" 200
17/Mar/2015:13:10:37 -0400 3 MB 0.033 seconds "GET /home/$user/public_html/wiki//load.php" 200

To view the peak memory amount that was allocated during a request you can add %M to the access log

;  %M: peak of memory allocated by PHP
;      it can accept the following format:
;      - %{bytes}M (default)
;      - %{kilobytes}M
;      - %{kilo}M
;      - %{megabytes}M
;      - %{mega}M

To view per request response times for PHP-FPM you can add %d, by default it will output response times in seconds, so 0.100 is 1/10 of a second or 100 milliseconds.

;  %d: time taken to serve the request
;      it can accept the following format:
;      - %{seconds}d (default)
;      - %{miliseconds}d
;      - %{mili}d
;      - %{microseconds}d
;      - %{micro}d