«« See previous post for getting nginx up and running. This post is about getting PHP running as a FastCGI.
PHP 5.3 with FastCGI Process Manager
Running PHP as a FastCGI (or even a regular CGI) means that it’s decoupled from the web server, and if you’ve historically run mod_php, then this is something you’ll have to get used to. For example, restarting your web server won’t refresh your PHP settings. The CGI listens on a port much like the web server itself does, and that’s how the web server passes requests though to PHP. There’s plenty of information on why this is good news, like here.
The nginx wiki has plenty of information and examples of running PHP as a FastCGI, but I had some bad experiences using these examples. Quite possibly this was due to my tuning it badly, but regardless, discovering PHP-FPM was a major result. Furthermore FPM is now bundled with PHP 5.3.3 – I thoroughly recommend, if you can upgrade to PHP 5.3.x that you do so. If you can’t, and you still want to use PHP-FPM, it’s a lot more effort to install and you may have to roll back your version of PHP 5.2.x – I won’t be covering that here, check the various patches here instead.
There doesn’t seem to be a huge amount of information about configuring PHP-FPM in PHP 5.3.3, so I’ll share my configs here. To start with building php-fpm from the downloaded PHP sources is as simple enabling the option. The rest of the build process is as normal, but you’ll have a php-fpm binary installed at /usr/local/sbin/php-fpm
$ ./configure --enable-fpm
The following is a single nginx server block, which defines a virtual host capable of executing PHP via FastCGI.
server { listen 80; server_name *.timwhitlock.info timwhitlock.info; root /home/vhosts/timwhitlock.info/httpdocs; access_log /home/vhosts/timwhitlock.info/log/access.log main; error_log /home/vhosts/timwhitlock.info/log/error.log warn; # Process PHP files with fastcgi location ~ .php$ { if ( !-f $request_filename ) { return 404; } include /etc/nginx/fastcgi_params; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; } location / { index index.php; } }
Notice the inclusion of /etc/nginx/fastcgi_params
. This file may be bundled with your nginx installation already. If not, it looks like this:
fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect #fastcgi_param REDIRECT_STATUS 200;
I also added the following lines, on the recommendation I found here (in fact this is probably what went wrong with my earlier experiments with FPM under 5.2.x). I recommend adding these lines.
fastcgi_connect_timeout 60; fastcgi_send_timeout 180; fastcgi_read_timeout 180; fastcgi_buffer_size 128k; fastcgi_buffers 4 256k; fastcgi_busy_buffers_size 256k; fastcgi_temp_file_write_size 256k; fastcgi_intercept_errors on;
That’s got nginx ready to pass PHP execution onto port 9000, so now we have to get PHP-FPM up and running on that port. PHP-FPM has it’s own configuration, which as of this new release has shifted from an XML format to the familiar ini style. This is a great move, firstly because it looks nicer, and secondly because it also allows us to add additional PHP ini settings.
My main php.ini
and php-fpm.conf
files are under /usr/local/etc
which is the default location. The php-fpm.conf
file contains global settings and settings for individual resource pools. Each pool listens on its own port, and can have its own PHP settings.
If you need to support multiple hosts as I do, then you’ll probably want each nginx server to pass PHP requests on to a different pool, specified by its port. To achieve this, I removed all resource pools from the main config and added a wild-card inclusion much like I did with the nginx config. My main php-fpm.conf
file looks like this:
[global] pid = /usr/local/var/run/php-fpm.pid error_log = /usr/local/var/log/php-fpm.log log_level = notice emergency_restart_threshold = 0 emergency_restart_interval = 0 process_control_timeout = 0 daemonize = yes ; pools defined in virtual hosts include=/home/vhosts/*/conf/php-fpm.include
Then each host has its own config in php-fpm.include
as follows.
[mypool] listen = 127.0.0.1:9000 listen.backlog = -1 listen.allowed_clients = 127.0.0.1 ; Unix user/group of processes user = nginx group = nginx ; Choose how the process manager will control the number of child processes. pm = dynamic pm.max_children = 50 pm.start_servers = 10 pm.min_spare_servers = 5 pm.max_spare_servers = 10 pm.max_requests = 100 ; Pass environment variables env[HOSTNAME] = $HOSTNAME env[PATH] = /usr/local/bin:/usr/bin:/bin env[TMP] = /tmp env[TMPDIR] = /tmp env[TEMP] = /tmp ; host-specific php ini settings here php_admin_value[open_basedir] = /home/vhosts/timwhitlock.info/httpdocs:/tmp
Any directives missing here were just left as default. Note that I set the user to nginx, although I don’t know whether this is a good idea, or not. This is possibly just a throw-back to my mod_php
days where PHP would always run as the apache
user.
Process manager tuning
There’s not much documentation on the pm.*
directives, namely max_children, start_servers, min_spare_servers, max_spare_servers, and max_requests
. However, they are analogous to other settings you may be familiar with. The well documented Apache directives, MaxClients, StartServers, MinSpareServers, MaxSpareServers and MaxRequestsPerChild
are worth a look to make sense of these options.
Once a process has been used it still occupies memory, even when idle, so you don’t want more of these processes running than your server can handle. I kept my spares low, and my max children under a number I was confident the server would have enough memory to cope with. This is not a particular area of expertise for me, so I suggest doing your own research.
To start up PHP, run the program telling it where your configs are:
# php-fpm -c /usr/local/etc -y /usr/local/etc/php-fpm.conf
If you need to reload any configurations, you can do a graceful reload will the kill command, as follows taking the process id from disk:
# cat /usr/local/var/run/php-fpm.pid | xargs kill -s USR2
Update
Since writing this I’ve improved my set up a bit
- Using this init.d script to start, stop and reload PHP configs
- Upgrading to PHP 5.3.6: the processes now show the pool names, which is handy
- I’m also using a Unix socket instead of a listening port
There’s also a init script here that you can place in /etc/init.d/phpfpm
http://svn.php.net/repository/php/php-src/branches/PHP_5_3/sapi/fpm/init.d.php-fpm.in
You’ll have to configure the @ variables
Olfosan:
There’s a good explanation of the IF statement here:
http://blog.digitalstruct.com/2010/07/12/getting-started-with-nginx-and-php-fpm/comment-page-1/#comment-40971
Nice write up you should update it with new nginx info as per http://wiki.nginx.org/Pitfalls
I recently implemented those new suggestions on nginx wiki in modified auto bash script install for nginx and php-fpm for centos http://vbtechsupport.com/796/
why are you writing this if statement in your config – this happens anyway in the server – the server will ALWAYS spit a 404 if a file is not found, so this is totally obsolete AND a serious performance problem, because it is done on every request!
people should start reading here about nginx:
http://wiki.nginx.org/Configuration
and AFTER reading the stuff over there start writing their own tutorials!
Don´t spread these errors!
@Ruo
This guide may help if you had problems while rebuilding the configuration script with buildconf.
http://daemoncoder.com/install/nginx-and-php-fpm-on-fedora-13
I guess you forgot to make a link from this page to this one: http://timwhitlock.info/blog/2010/08/21/varnish-with-php-and-wordpress/
Am I wright?
Congratulations for the very well written content by the way!
Over?
I follow the linode’s to install php5.3.3, but it didn’t work.
Now I just use the php5.2.4 with php-fpm.
Also I’m new gay to learn liunx, did u have any rpm package to install the lnmp quickly.
I found a great resource configuring fast-cgi on fedora 13 box (in case someone is wondering)
http://library.linode.com/web-servers/nginx/php-fastcgi/fedora-13