I still got sites running Apache, but all new projects are launched with Nginx. I don't need many of the features that Apache offers, and the speed gain of Nginx is just tremendous. Once you've experienced it, I doubt you'll want to go back.

Update - May 2nd, 2013

The official CakePHP documentation now includes a good Nginx section. This article is hence deprecated and should only be looked at for Cake 1.3 installations.

Update - Feb 24th, 2013

Chris Hartjes takes a similar approach in articles written way before mine, be sure to check it out!

Continuing

Even though there has been quite some fuzz about Nginx and I bet most of you have at least heard of it by now, I think the acceptance is still a bit low.

I'd like to help that process along by providing developers a simple yet effective example.

Maybe you'll play with it on your local box - and eventually decide to go production. Who knows.

Let me show you how easy it is to get hooked to the power of Nginx.

In this article I'm demonstrating a CakePHP setup, but 1 slight modification and this applies to pretty much any PHP Framework.

So there are a few differences from your typical Apache setup that I'd like to highlight.

Install Nginx

If you're running Ubuntu like me it helps to have Karmic or higher. Then just type:

$ aptitude install nginx

Other operating systems: it shouldn't be much harder then that, just replace aptitude with your package manager.

If you find yourself compiling you're on the wrong track, and going to spe nd way too much time on this.

Don't forget to shut down any existing web servers you may have.

PHP FastCGI: spawn-fcgi

In this setup, PHP is daemonized and keeps running as a process, listening to a socket.

Nginx will be configured to pass any *.php requests to this PHP process. Normally PHP would have to be fired up all the time. But now it resides in memory.

To install spawn-fcgi in Ubuntu you'd do:

$ aptitude install spawn-fcgi php5-cgi

# It doesn't provide a startup script yet. Here's how to get one:
$ curl https://raw.github.com/kvz/deprecated/kvzlib/configs/spawnfcgi_initd -ko /etc/init.d/spawn-fcgi \
 && chmod a+x $_
$ update-rc.d spawn-fcgi defaults

Now start it with:

$ /etc/init.d/spawn-fcgi start

Excellent. PHP is listening on port 9000 for incoming Nginx jobs.

You can configure your new PHP install like you're used to.

Only in this directory: /etc/php5/cgi/ instead of this one /etc/php5/apache2/

Alternative: php-fpm

There also is php-fpm. Pretty much does the same thing, but faster.

Unfortunately at the time of writing I'm experiencing too many crashes for it to be recommendable. This will probably change soon though.

HtAccess

It's true that Nginx doesn't support .htaccess, but to be honest: .htaccess files are the worst.

The additional recursive dir-stats, I/O, & processing involved with every request, is equal to the exact amount of punches in the face.

That it doesn't support .htaccess does not imply however, that you can't do rewrites and all the other fancy things you could do with .htaccess files.

Just slightly modify the syntax, and place those new rules in your Nginx VHost.

As a present, I've already converted the .htaccess rules required to run CakePHP, and put them in the Nginx VHost example below.

Nginx Vhost

VHost concept works the same as Apache. Have 1 for every site.

Save it in /etc/nginx/sites-available/site. To activate, symlink it to /etc/nginx/sites-enabled/site

run:

$ /etc/init.d/nginx reload

..and you're in business. Use

$ tail -f /var/log/nginx/*.log

to see what's going on.

You don't need to change Nginx's main config, it's tight by default so just stick with your VHost for now.

Here's what a fully working CakePHP VHost looks like:

server {
    listen      80;
    server_name example.com www.example.com;
    access_log  /var/log/nginx/example.com.access.log;
    error_log   /var/log/nginx/example.com.error.log;
    rewrite_log on;
    root        /var/www/example.com/app/webroot;
    index       index.php index.html index.htm;

    # Not found this on disk?
    # Feed to CakePHP for further processing!
    if (!-e $request_filename) {
        rewrite ^/(.+)$ /index.php?url=$1 last;
        break;
    }

    # Pass the PHP scripts to FastCGI server
    # listening on 127.0.0.1:9000
    location ~ \.php$ {
        # fastcgi_pass   unix:/tmp/php-fastcgi.sock;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_intercept_errors on; # to support 404s for PHP files not found
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }

    # Static files.
    # Set expire headers, Turn off access log
    location ~* \favicon.ico$ {
        access_log off;
        expires 1d;
        add_header Cache-Control public;
    }
    location ~ ^/(img|cjs|ccss)/ {
        access_log off;
        expires 7d;
        add_header Cache-Control public;
    }

    # Deny access to .htaccess files,
    # git & svn repositories, etc
    location ~ /(\.ht|\.git|\.svn) {
        deny  all;
    }
}

Notes about the example

  • Nginx config is simple & powerful. If you want you can use if statements and put some very basic logic in there.
  • In this example the /app/webroot is the document root. Some people may have a / as their CakePHP webroot or even /app. But I recommend changing that to /app/webroot so you're not exposing any more PHP files then is strictly required.
  • Notice how this config turns off access log for some static files? How cool is that?!
  • Checkout how simple it is to set expire headers for different content types
  • Change example.com to your domainname

Free Bonus

Here's a VHost if you'd want to use phpmyadmin as installed in by Ubuntu's Apt:

server {
    listen       80;
    server_name  phpmyadmin.example.com;
    root         /usr/share/phpmyadmin;
    index        index.php;

    # Add your IP to the allow list!
    location / {
        allow 123.123.123.123;
        deny all;
    }

    location ~ \.php$ {
        index          index.php index.html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_intercept_errors on; # to support 404s for PHP files not found
        include        fastcgi_params;
    }
}

I'm keeping the larger code blocks on GitHub so it'll be really easy for you to download, fork etc.

For instance I have another CakePHP configuration that's a bit bigger - shows you some other stuff you can do with Nginx here

That's it

Now go out there, have fun, tell me your findings.