← All posts

Nginx. Using PHP in FastCGI Mode with php-fpm

php-fastcgi

I had Apache 2.2 and mod_php installed. Since Apache eats up quite a lot of resources, I decided to gradually move the projects on my server to Nginx + PHP-FastCGI, with php-fpm as the spawner.

In brief, what is FastCGI, and why is it better than mod_php?

FastCGI is a high-performance, scalable interface for communication between a web server and applications, a further development of CGI technology. You can find more detailed information about FastCGI on the official website or on Wikipedia. The main advantage of FastCGI is that it isolates the dynamic language from the web server. For example, a FastCGI process can run as a user other than the web server’s user, and the process can also be in a different chroot from the web server. Among other things, this technology allows web servers and CGI processes (PHP scripts, for instance) to run on different hosts, which improves scalability and also contributes to security without a significant loss of performance.

So why do we need php-fpm if PHP already supports running in FastCGI mode?

php-fpm is a patch for PHP that allows PHP to be used as a FastCGI process on high-load systems. It fixes a number of problems that get in the way of using PHP in FastCGI mode. Andrey Nigmatulin introduced the php-fpm patch set for PHP 4/5, addressing a number of problems that prevent PHP from being used in FastCGI mode on high-load systems. php-fpm features: * Process management. The ability to “gracefully” stop and restart PHP workers without losing requests. The ability to gracefully update the configuration and binary without losing requests; * Restricting the IP addresses from which web server requests can arrive; * A dynamic number of processes depending on load (TODO); * Running workers with different uid/gid/chroot/environment settings and different php.ini options; * Logging worker processes’ stdout & stderr; * Emergency restart of all processes in the event of accidental corruption of the shared memory opcode cache, if an accelerator is used; * Forcibly terminating hung processes if set_time_limit() does not work (TODO); http://php-fpm.org/wiki/What_is_PHP-FPM

Andrey Nigmatulin / php-fpm / PHPConf 08 from Mihail Andreev on Vimeo.

By the way, I made an appearance in the video too: at 5 minutes and 20 seconds, I walk in front of the camera wearing a suit and a red T-shirt… :D

All right, let’s get started!

Installing Nginx

Actually, I already had Nginx installed, but for the sake of completeness, I’ll explain how to install it too. Depending on the functionality you need or the stability of the release, you need to choose a suitable version of Nginx. The stable version is in the “/usr/ports/www/nginx/” directory, and the newer one is in “/usr/ports/www/nginx-devel/”. I have the latter installed.


# cd /usr/ports/www/nginx-devel/
# make install clean

That’s it, Nginx is installed. Add it to startup:


# echo 'nginx_enable="YES"' >> /etc/rc.conf

Installing php-fpm

The process involves patching and reinstalling the PHP interpreter with FastCGI and php-fpm support.

Installing from source

Go to the official PHP website and download the version of the PHP interpreter you need from http://www.php.net/downloads.php. In my case, it’s PHP 5.2.10.


# cd /tmp
# fetch http://ru2.php.net/get/php-5.2.10.tar.gz/from/ru.php.net/mirror

Go to the downloads section of the php-fpm project’s official website, http://php-fpm.org/download, and choose the patch version that matches your PHP interpreter. I’m using PHP 5.2.10, so that’s the one I’ll install.


# cd /tmp
# fetch http://php-fpm.org/downloads/php-5.2.10-fpm-0.5.13.diff.gz
# tar -xzf php-5.2.10.tar.gz
# gzip -cd php-5.2.10-fpm-0.5.13.diff.gz | patch -d php-5.2.10 -p1
# cd php-5.2.10
# ./configure --enable-fastcgi --enable-fpm
# make all install

Now let’s copy the php-fpm initialization script to the “/usr/local/etc/rc.d” directory and give it execute permissions:


# cp /tmp/php-5.2.10/sapi/cgi/fpm/php-fpm /usr/local/etc/rc.d/
# chmod +x /usr/local/etc/rc.d/php-fpm

Installing from ports

It’s all much simpler here… :)


# cd /usr/ports/lang/
# fetch http://php-fpm.org/downloads/freebsd-port/php-5.2.10-fpm-0.5.13.tar.gz
# tar -xzvf php-5.2.10-fpm-0.5.13.tar.gz
# rm php-5.2.10-fpm-0.5.13.tar.gz
# cd php5-fpm
# make install

Finishing the installation

After installation, check the PHP version:


# php -v
PHP 5.2.10 (cli) (built: Sep  2 2009 12:46:58)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies

If “built” shows today’s date, everything is OK. If not, leave a comment and I’ll help you figure it out.
I’ve installed it both from source and from ports, so I’ve tested all of this myself! :)

Let’s add it to startup:


# echo 'php_fpm_enable="YES"' >> /etc/rc.conf

Configuring Nginx

Now let’s configure Nginx. Edit the configuration file “/usr/local/etc/nginx/nginx.conf” or your “vhost”:


server {

        listen 80;
        server_name demo.adw0rd.ru;

        location ~* \.(jpg|jpeg|gif|png|ico|css|zip|js|swf)$ {
                root /home/adw0rd/adw0rd.ru/demo;
        }

        location / {
            fastcgi_pass   82.146.63.195:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /home/adw0rd/adw0rd.ru/demo$fastcgi_script_name;
            include        fastcgi_params;
        }
}

A little more detail on configuring nginx can be found here and here.

Configuring php-fpm

I’ll show only the parts of the configuration that differ from “php-fpm.conf.default”. You can get the full configuration here.


<value name="listen_options">

        Set listen(2) backlog
        <value name="backlog">-1</value>

        Set permissions for unix socket, if one used.
        In Linux read/write permissions must be set in order to allow connections from web server.
        Many BSD-derrived systems allow connections regardless of permissions.
        <value name="owner">www</value>
        <value name="group">www</value>
        <value name="mode">0666</value>
</value>
...
Unix user of processes
<value name="user">www</value>

Unix group of processes
<value name="group">www</value>
...
Comma separated list of ipv4 addresses of FastCGI clients that allowed to connect.
Equivalent to FCGI_WEB_SERVER_ADDRS environment in original php.fcgi (5.2.2+)
Makes sense only with AF_INET listening socket.
<value name="allowed_clients">127.0.0.1,82.146.63.195</value>

“82.146.63.195” is the IP address of my server running nginx. That’s the one we’ll allow access to.

Starting up

Now all that’s left is to start nginx and php-fpm:


/usr/local/etc/rc.d/nginx restart
/usr/local/etc/rc.d/php-fpm restart

If it doesn’t start, check “/var/log/php-fpm.log”. If there is no log file at all, create it and set write permissions.
That’s all. In the next article, I’ll talk about spawn-fcgi (formerly part of lighttpd).

Comments are closed. Read the original discussion in Russian →