- Published on
CakePHP and Nginx
- Authors

- Name
- Kevin van Zonneveld
- @kvz
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 than that, just replace aptitude with your package manager.
If you find yourself compiling you're on the wrong track, and going to spend 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 than 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.
Legacy Comments (17)
These comments were imported from the previous blog system (Disqus).
Thanks,
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 :)
@ 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.
I 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.
@ Joris van de Sande: Under heavy load I got a lot of these: http://bin.cakephp.org/view...
And then php-fpm would just be gone.
I 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.
What\'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:
@ 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.
Good 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.
I\'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.
What would be useful is a lighttpd - apache - nginx config converter to allow you to quickly do benchmarking and regression testing on all platforms.
Again a nice article!
Minor typo:
wget -0 should be wget -O
@ 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!
Hi, this article is very helpful. I was trying to restrict some additional files from the access log and I can't seem to get the right syntax.
I want to turn off logging for any hits to files in the '/sqlview/' folder off of the web root. Here's what I tried, with no luck:
location ~* /sqlview/ {
access_log off;
}
Any ideas where I'm going wrong?
Thanks!
Could it be there's PHP in /sqlview/ ?
You probably have a different location for PHP and Nginx only executes 1 (best matching) location per request.
The order in which it will pick locations can be found in the documentation wiki.
I've used your Nginx CakePHP Vhost template with success but now it seems that the newer version of CakePHP (1.3.3) doesn't quite work right.
It might be that is has nothing to do with your Vhost template and that it is an error with FastCGI or Nginx.
The error is the following:
I get a 502 with this in my /var/log/sitexyz.error.log:
2010/09/16 15:58:59 [error] 2792#0: *81 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 172.20.0.2, server: testserver.xyz, request: "GET / HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "testserver.xyz"
Any thoughts?
Nevermind my last comment. Everything works.
Thanks for the great post. It does work for me with php-fpm and nginx however I have problems with static files. The part about /img/cjs/ccss folders does not work and my images from CSS don't load which are in fact under /img/
using cake 1.2.9 stable.
thanks again.
update to my previous comment.
turns out its not really the whole problem. The problem is the images referenced in CSS files don't work anymore.
Also it seems authentication does not work although cookies are set... still investigating.