nginx configuration gotchas

Tuesday, April 5. 2011

After running away screaming from Zend_XmlRpc we migrated of our internal webservices are RESTful nowadays — which implies that we make heavy use of HTTP status codes and so on.

On the PHP side of things we implemented almost all of those webservices using the Zend Framework where some parts are replaced by in-house replacements (mostly stripped-down and optimized versions equivalents of Zend_Foo) and a couple nifty PEAR packages.

RESTful — how does it work?

Building a RESTful API means to adhere to the HTTP standard. URLs are resources and the appropriate methods (DELETE, GET, POST, PUT) are used on them. Add status codes in the mix and ready you are.

To keep it simple for this blog post the following status codes are more or less relevant for a read-only (GET) API:

  • 200: it's A-OK
  • 400: a bad request, e.g. a parameter missing
  • 401: unauthorized
  • 404: nothing was found

... and this is just the beginning — check out a complete list of HTTP status codes.


To serve PHP almost all of our application servers are setup like the following:

  1. nginx in the front
  2. php (fpm) processes in the back

Nginx and PHP are glued together using fastcgi (and unix-domain sockets).

For an indepth example of our setup check out the nginx-app and php-fpm recipes (along with our launchpad repository).


The other day, I noticed that for some reason whenever our API returned an error — e.g. a 404, for an empty result — it would display a standard nginx error page and not the actual response.


Digging around in /etc/nginx/fastcgi_params, I discovered the following:

fastcgi_intercept_errors on;

So what this does is that it intercepts any errors from the PHP backends and attempts to display an nginx error page. All errors may include the various PHP parse errors but apparently also a PHP generated page with a 404 status code.

So for example, the following code served by a PHP backend triggers the nginx page:

header("HTTP/1.1 404 Not Found);

The obvious fix seems simple:

fastcgi_intercept_errors off;

Sidenote: I think a similar issue might be in nginx's proxy_intercept_errors.

For both directives the manual suggests that they will intercept any status code higher than 400 — or 4xx and 5xx. But that's not all.

Tell me why?!

Reviewing the manual, I noticed that nginx will only act on fastcgi_intercept_errors on; when an error_page is (previously) defined. Checking out the rest of my sites configuration, the following part is to blame:

location / {
    error_page 404 /index.php;

    include /etc/nginx/fastcgi_params;

    fastcgi_pass  phpfpm;
    fastcgi_index index.php;

    fastcgi_param SCRIPT_FILENAME /var/www/current/www/index.php;

    index  index.php index.html index.htm;

So indeed the error_page 404 /index.php is what set it all off to begin with. And that's what I ended up removing, though it doesn't hurt to understand the implications of fastcgi_intercept_errors.

I think historically we used the 404 error handler as a cheap excuse for a rewrite rule since we only serve dynamically generated pages (and super-SEO-friendly URLs) to begin with. But that doesn't seem to be necessary — testing will be required.


The moral of the story is: nginx is really never to blame. ;-)

This is precisly what happens when you copy/paste configurations from the Internetz and don't review each and every single line to understand the full scope. In the end this was more or less a picnic on my part but I wanted to share it anyway because it was one of those WTF-moments for me.

PHP FastCGI woes!

Monday, January 26. 2009

Those of you who run high traffic websites, have probably tried php-cgi/fcgi down the road. And most of us, have gone back to Apache.

But now — actually since the middle of 2007 — there's light at the end of the tunnel. I read a blog post by Evert Pot's last night (Apache speed and reverse proxies). Evert noted that he tried to use Lighttpd and php-fcgi, all the infamouse tricks with, etc.. — and failed.

He referenced my own blog post where I shared a similar experience; on a sidenote, I'm very glad I'm not the only one who's had these issues. One of the commenters on Evert's blog suggested that he used a project called php-fpm, which I had never heard of to date.

Drum roll!

So anyway, php-fpm is the efforts of Andrei Nigmatulin and they seem to be the end to all those problems. I've spend a few hours last night reading up on it (with the help of Google Translate) and doing a test install, and it seemed pretty cool. I emailed Andrei and suggested that he added links to Google Translate from all pages but he instead setup a wiki. Wee!

I spent two hours over the course of this day moving the pages into the wiki. And the result is:

Quo vadis?

First off, let me just add that the wiki is work in progress, and you are welcome to contribute! A lot of English is straight Google Translate which is naturally not perfect.

So far, I've been moving all Russian pages to English ones, I'm hoping Andrei feels guilty (:-)) when he sees my pages and adds Russian back in. I've also emailed someone who translated the brief HowTo into Chinese!

Further more, I have not yet tried php-fpm but I'm excited and will let you know what the results are. If you are a step ahead of me (Well, I've overslept this thing since 2007!), please share your experience in the comment section!