Apache and lighttpd replaced by nginx for PHP application

A while back I wrote an article Switching from Apache HTTP Server to Lighttpd – Installing Lighttpd. Back then I migrated static stuff to lighttpd but left the dynamic stuff (PHP) with Apache.

I was never really satisfied with the speed of our system under load. I tried and tried. I optimized a lot of stuff in the backend and with the database. Most of the time I found a switch to make the system just a bit faster. Read Retrospective on three years of Seagull development if you are interested in the whole story.

In the last couple of weeks I ran out of ideas on where to improve next (without the need of rewriting too much code). I remembered using Squid years ago. I had a look at the newest version (3.0) and my interest in Squid stopped pretty soon after reading through the documentation. It was just not the software I needed.

I dived into spreading the load to multiple backends using HAproxy which by the way has a super active community. Check the mailinglist. The maintainer Willy is doing a great job. Learning about HAproxy I stumbled across the webserver nginx (pronounced engine x) numerous times. Learning about nginx I stumbled across the reverse proxy Varnish which is the proxy solution I hoped Squid would be. Furtherdown the line I ran into PHP-FPM – the PHP FastCGI Process Manager – which should not stay unmentioned.

So I read lots of blog posts, mails from mailinglists, documentation, articles, visited several forums and also learned many new things in a few wikis. So after getting the idea I had my stack together: Varnish -> HAproxy -> nginx -> PHP -> MySQL

Time to test it out! Varnish comes in a relatively uptodate package for my favorite distribution OpenSuSE (currently running 10.3 on 6 systems). HAproxy is available in a fresh version. nginx is theoretically available. I cannot install it though because of a package management conflict. So I downloaded the source for the newest stable version (0.6.3 as time of writing) and compiled it.

wget http://sysoev.ru/nginx/nginx-0.6.32.tar.gz
tar xzvf nginx-0.6.32.tar.gz
cd nginx-0.6.32
./configure --prefix=/opt/software/nginx-0.6.32 --user=nginx --group=nginx --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module
make && make install

I did not need to install any extra packages. Frankly spoken I do have all the packages for compilation of C/C++ installed.

cd /opt/software
ln -s /opt/software/nginx-0.6.32 nginx

I always set a symlink to the currently used package. That way it is easy to replace the package when new versions come out. I can compile and install the new version and just switch the symlink.

Next thing I had to compile was a patched PHP version. So download the sources at php.net and the patches at the PHP-FPM site.

Unpack the PHP source:

tar xjvf php-5.2.6.tar.bz2

Patch the source:

gzip -cd php-5.2.6-fpm-0.5.8.diff.gz | patch -d php-5.2.6 -p1

Configure PHP (adjust your settings accordingly):

LDFLAGS="-L/usr/lib64" ./configure --with-curl --disable-debug --enable-libxml --enable-session --with-pcre-regex --enable-xml --with-bz2 --with-zlib --enable-exif --enable-inline-optimization --enable-soap --enable-sockets --with-xmlrpc --without-pear --with-libdir=lib64 --with-mysql --with-mysqli --enable-mbstring --with-mcrypt --with-mhash --with-mime-magic --with-jpeg-dir=/usr/lib64 --with-png-dir=/usr/lib64 --with-gd --enable-gd-native-ttf --with-ttf --with-freetype-dir --enable-ftp --enable-zend-multibyte --with-openssl --enable-force-cgi-redirect --with-pcre-regex --without-sqlite --without-mm --enable-fastcgi --enable-bcmath --enable-fpm --quiet --prefix=/opt/software/php5.2.6-fpm

Compile and install:

make & make install

Adjust the PHP-FPM settings to fit your needs. You can find more info on this and related subjects in the PHP-FPM documentation.

vim /opt/software/php/etc/php-fpm.conf

Start PHP-FPM:

/opt/software/php/bin/php-cgi --fpm

Have a look in the log files:

/opt/software/php/logs/php-fpm.log

Now you can connect through your webserver to fast-cgi processes. I use nginx as webserver (see above). Advantages and disadvantes of fast-cgi vs. mod-based approaches et al have been covered elsewhere. For me this makes perfectly sense and works extremly well.

After playing around with Varnish for a while I decided I do not need HAProxy ATM. Varnish can do all the decisions I need to make based on HTTP headers. I configured Varnish’s config file (here: vcl.conf) by reading lots of examples on the net and trial and error.

If I find more time and anyone is interested I post more details on the configuration of nginx and Varnish. But for now I want to publish this post as it has been sitting here for a while already.

PS: If people say content is king they are absolutely right. But never forget in the internet speed is Kaiser!


10 Responses to “Apache and lighttpd replaced by nginx for PHP application”

  • 1 Marco Says:

    Hmm, momentan habe ich nur nginx -> mehrere Apaches. Die Apaches auch nur wegen >50 mod_rewrite Rules. Nginx wird den Part auch irgendwann übernehmen.

    Load-Balancing läuft ebenfalls über nginx, aber das ist nicht ganz optimal implementiert. Über kurz oder lang wird das HAproxy machen müssen, wenn sich das nicht ändert.

    Varnish kenn ich zwar, aber als Proxy kann man ja auch nginx nutzen. Das funktioniert auch einwandfrei, noch eine Software muss ich da nicht unbedingt nutzen :)

  • 2 Fabio Says:

    Ich hatte letztens das erste Mal über das Proxy Modul von nginx gelesen. Da hieß es noch, dass das Modul nicht annähernd einsatzbereit sei. Was benutzt Du da genau?

  • 3 Marco Says:

    Ich liefer alle statischen Sachen direkt aus und alles andere geht über das Proxy-Modul an die Upstream-Server, also die Apaches. Einzig der Load-Balancing Algorithmus ist nicht ganz ideal, aber das ist noch nicht mal bei mir besonders problematisch. Könnte kritisch sein, wenn man viele lange Requests hat.

    Für Einsatzbereit halte ich das aufjedenfall, habe aber die 0.7er Version, die wirklich zuverlässig ist. Hatte da noch keinen Ausfall.

  • 4 hyem Says:

    Wow… nice story… neary same as what I did.. :D
    anyway… can You Give me your config file for a smple?
    including config for nginx, Varnish, php.ini, and my.cnf..
    humm can you make some benchark resoult?

    regards

  • 5 Fabio Says:

    @hyem: I will write a follow-up article with config examples. I am not sure if I find the time for benchmarks.

  • 6 Nathan Delligatti Says:

    Effectively I arrived below on another write-up but ended up staying for 20 minutes reading your stuff! Enjoyed it :-D

  • 7 Fabio Says:

    Please note this article is totally out of date by now. :(

    OpenSuSE is available in version 11.3 which brings *all* the software ready to install through the package manager.

    The fast processing manager (FPM) is integrated into PHP5.3.3 so you do not have to patch anymore.

    I am still using the same stack as described above but I switch the order. Now HAproxy is listening on port 80. Requests for static stuff are routed to Varnish. If the requested stuff is cached Varnish serves is otherwise the request is passed to nginx. Requests for dynamic things is passed directly from HAproxy to nginx.

  • 8 Alex Says:

    Why did you replace lighttpd? It runs fcgi processes very well and manages them itself. Seems lots of work and extra complication. What’s the payoff?

  • 9 Fabio Says:

    @alex: Lighttpd was not running stable at that point for me. nginx has a super light foot-print, is extremly stable, fast and the configuration options are endless but easy to figure out. For my case – in many different scenarios – it has been a great piece of software and as such solution. I don´t wanna miss it in my stack.

  • 10 Edemilson Lima Says:

    There is a good benchmark test comparing Varnish, LightHTTPd and Nginx at:

    http://nbonvin.wordpress.com/2011/03/24/serving-small-static-files-which-server-to-use/

Leave a Reply