» CakePHP and Nginx

On twitter

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.

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:
wget -O/etc/init.d/spawn-fcgi http://github.com/kvz/kvzlib/raw/master/configs/spawnfcgi_initd
chmod u+x /etc/init.d/spawn-fcgi
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

  1. Nginx config is simple & powerful. If you want you can use if statements and put some very basic logic in there.
  2. 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.
  3. Notice how this config turns off access log for some static files? How cool is that?!
  4. Checkout how simple it is to set expire headers for different content types
  5. Change example.com to your domainname
- Update #1: Chris Hartjes takes a similar approach in articles written way before mine, be sure to check it out!

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, play, tell me your findings. 

If you have cool additions let me now, and we'll work together to build the:

 

Ultimate CakePHP Nginx Config
One Config to Rule Them All

 

Stay up to date

You can track my blog rss articles and rss comments. You may also find my rss bookmarks interesting. Or twitter Follow me on Twitter


Like this Article?

Your money is no good here, but
you can boost morale by spreading the word! : )


tags: php, nginx, cakephp, apache, performance
category: Programming - PHP - CakePHP
read: 5,586 times

Add comment

(required, shown)(required, not shown)for syntax highlighting

[CODE="Javascript"]
your_code_here();
[/CODE]

Replace "Javascript"
with "php", "text", etc.
code (to make sure you are not a spammer)

 Track replies: rss feed comments feed

Comments

#11. Kevin on 28 February 2010

Twitter.com: kvz@ till: besides the logs I posted I have not further details on the crashes. I'll try fpm again some time soon and see if I can really get to the bottom of it.

@ jefftrackaid: For loadbalancing I mostly use lvs right now. This blog is powered by varnish as well, but I found you can tune Nginx to server static files so fast; the need for varnish diminishes. I will do another post on that topic later

@ Erwin Bleeker: Good catch Bleeker! Thanks a lot!

#10. Erwin Bleeker on 26 February 2010

Gravatar.com: Erwin BleekerAgain a nice article!
Minor typo:
wget -0 should be wget -O

#9. jeffatrackaid on 26 February 2010

Gravatar.com: jeffatrackaidI've not made the wholesale switch to nginx yet. There are a few projects where we have used it but have been sticking with lighttpd for now.

Like PHP op-code caches, I find that HTTP server performance varies significantly depending on the underlying application.

Another tool we've started exploring more is varnish for HTTP acceleration and most recently Citrix NetScaler for Layer 7 load balancing.
... [more]
What would be useful is a lighttpd - apache - nginx config converter to allow you to quickly do benchmarking and regression testing on all platforms.

#8. till on 26 February 2010

Gravatar.com: tillGood to know, I'm somewhat hesitant to adjust my setup now, but who knows. I'm also interested in fpm. I have a few builds and tests, so far it's looking very, very good.

Not sure about the unstableness, maybe you can detail what you experienced. I didn't see anything yet. I've been "attacking" the test server with siege and didn't see any drops.

For me, fpm is great because of the management. E.g., the graceful restarts and all.

#7. Kevin on 26 February 2010

Twitter.com: kvz@ till: Hey. The busiest box I have that runs this config delivers 80Mbit of php generated html (admittedly some pics are in there but not much: expire headers take care of that).
Had similar issues on Jaunty but after upgrading to Karmic we were all good.

@ Joris van de Sande: Cool let me know how it works out. I intend to switch to fpm as soon as I get it stable.

#6. till on 26 February 2010

Gravatar.com: tillWhat's the most busy site you run using this? From my experience (on Ubuntu and FreeBSD), the webserver (nginx or lighttpd) and spawn-fcgi loose connections sooner or later and I have to restart it all.

PHP processes idle, but the webserver claims it cannot get to them.

I managed to set it up using a socket instead, no spawn-fcgi, see my blog entry for more details:
... [more]
http://till.klampaeckel.de/blog/archives/44-Nginx+PHP+FastCGI-Testing-your-web-application-with-bleeding-edge-PHP.html

#5. Joris van de Sande on 26 February 2010

Gravatar.com: Joris van de SandeI will try to stress my home server when I can find some time for it. I haven't tested php-fpm under heavy load yet.

#4. Kevin on 26 February 2010

Twitter.com: kvz@ Joris van de Sande: Under heavy load I got a lot of these: http://bin.cakephp.org/view/363652519
And then php-fpm would just be gone.

#3. Joris van de Sande on 26 February 2010

Gravatar.com: Joris van de SandeI have been running php-fpm for over a year now (first with php 5.2, now it's running 5..3.1) with apache2 as webserver. In my experience it's very stable, it has never crashed on my home server. It works better than the integrated fast-cgi server in PHP (it dies after 500 requests).

What type of crashes are you experiencing?

According to http://php-fpm.org/download/ , php-fpm should be integrated in PHP as of version 5.3.3.

#2. Kevin on 25 February 2010

Twitter.com: kvz@ Rachman Chavik: thanks, when you do, let me know how it goes. I'm glad to help out and I'd like to perfect the article based on your feedback.

#1. Rachman Chavik on 25 February 2010

Gravatar.com: Rachman ChavikThanks,

Played around with nginx + cakephp a few months back to no avail. But now your post make it seem so simple! Now to find the time to test :)