Nginx w/ fastcgi php-fpm - Results & Problem

Events happening in the community are now at Drupal community events on www.drupal.org.
mesch's picture

I've been using nginx as a static file server and a reverse proxy to apache mod_php for a while now and it's been great. I had some time to experiment with the full monty of nginx recently on a development box. I thought I'd share some of my simple benchmarks vis-a-vis my old setup, and also pose a question re: a problem I've encountered. First the benchmarks:

Run VIRT RES SHR DAT 50% response time
mod_php ~50M 21-32M ~3.5M 26-37M 550ms
nginx php-fpm ~50M 20-30M ~3.2M 24-35M 570ms
mod_php w/ apc ~75M 25-27M ~14M 18-22M 250ms
nginx php-fpm w/ apc ~72M 20-25M 13M 14-20M 270ms

For the above:
- max fpm children = max apache clients
- ab -c5 -n10000
- address tested is the front page of a drupal6 instance on localhost with ~80 modules installed including cck, views, ubercart, and two large custom application-specific modules written by yours truly
- Server caching (e.g. nginx microcache) and Drupal page caching turned off

Conclusions:
- APC is fantastic (we knew that already).
- mod_php is slightly faster at php than php-fpm, though the difference is small. This is consistent with what I've read elsewhere.
- php-fpm uses less RAM than mod_php (~3-5M less per process in this test, which is not insignificant).

Couple these results with nginx superiority at static file serving and other goodies, and now that fpm is baked into php itself, I think I'm going to go ahead with this setup on production. For those that want to stick with apache, I should also point out that you can use fastcgi instead of mod_php with apache as well, which will cut down on apache memory use vis-a-vis static file serving considerably.

I do, however, have one problem. For some reason all my links include index.php. So instead of "http://localhost/?q=node/15", I get "http://localhost/index.php?q=node/15". Drupal6 won't let me enable clean URLs. I'm pretty sure this is a problem w/ my nginx config, as this issue isn't occuring w/ apache. Interestingly, it also isn't happening with a drupal7 instance under nginx, just drupal 6.

I'm using perusio's config for nginx, with microcaching turned off. This appears to be a rewrite issue, but I can't put my finger on it. Among other things, I tried:
- disabling any drupal modules (such as Global Redirect) that might cause problems
- adding an explicit base url to "settings.php"

I'd greatly appreciate any ideas on how to fix this. I feel I'm missing something pretty basic!

Comments

all my links include index.php

Peter Bowey's picture

I have seen that issue myself, in times past with nginx

Check that you are using something like this:

    # catch all unspecified requests
    location / {
        if ( $http_user_agent ~* wget ) {
            return 403;
        }
        try_files $uri @drupal;     # Using D6 request_path() method
    }
    # Send all not cached requests to drupal with clean URLs support.
    location @drupal {
        error_page 418 = @nobots;
        if ($args) {
            return 418;
        }
        rewrite ^/(.*)$ /index.php?q=$1 last;
    }
    # Send all known bots to $args free URLs.
    location @nobots {
        if ($no_bot_search) {
            rewrite ^ $scheme://$host$uri? permanent;
        }
        rewrite ^/(.*)$ /index.php?q=$1 last;
    }
    # send all non-static requests to php-fpm, restricted to known php files
    #   Notes: because of a new custom request_path() in Drupal 6 'bootstrap.inc'
    #   we can use the preferred; " try_files $uri $uri/ @drupal; "
    location = /index.php {
    ...
    ... 'usual fastcgi_ stuff follows'
    ...

It is a 'clean urls / permalink' issue you have with current your nginx setup.

See this link [below] for some working examples [thanks to omega8cc]

https://github.com/omega8cc/nginx-for-drupal

Peter

--
Linux: Web Developer
Peter Bowey Computer Solutions
Australia: GMT+9:30
(¯`·..·[ Peter ]·..·´¯)

Still no dice. Instead of

mesch's picture

Still no dice. Instead of using rewrite, perusio's config uses try_files as follows:

try_files $uri /index.php?q=$no_slash_uri&$args;

... where $no_slash_uri is define elsewhere as

map $uri $no_slash_uri {
    ~^/(?<no_slash>.*)$ $no_slash;
}

And the /index.php location as follows:
location = /index.php {
  fastcgi_pass phpcgi;
}

Here are the fastcgi_params which are included at the http level in nginx.conf:

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;
fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;

## PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

Great post

jasmineah's picture

I enjoyed reading your post MEsch as this is something am currently working on. I am in the process to trying to get nginx work as a reverse proxy but since I've read your post and thinking of giving nginx another go without apache. Have you experienced any other problems with your nginx setup on a d7 site that is? Further, do you think the benefits of having both nginx and apache outweighs using either one of them on it's own?

Glad you enjoyed it

mesch's picture

Glad you enjoyed it jasmineah.

I haven't experienced any issues with my current production setup (nginx as static file server and reverse proxy to apache2 mod_php). I only host drupal6 instances on that server at the moment, but I wouldn't anticipate drupal7 creating further issues. I'm sure the more experienced server people in the group can better answer your question.

Re: your second question, there seems to be a tradeoff between speed and memory use among mod_php and php-fpm. I have a production VPS, and for me the difference in speed is so small as to be insignificant for my needs, whereas the savings in memory from php-fpm should allow me to add some precious additional processes. Overall I'll be able to serve more requests than before.

If you want to stick with apache only but want more efficient static file serving, you can use worker instead of prefork. I have no experience with this, but have read the reduction in memory use is substantial. I'd also imagine the php performance would be similar to nginx php-fpm, but again, I've never looked into it.

Good luck! I'd recommend starting with one of the configs available here. I've personally found them invaluable in learning how nginx works and avoiding common pitfalls.

That's strange

perusio's picture

In my config index.php is off limits. If you really need it, you should comment out the internal line in the index.php location.

Are you sure that this is not a browser problem? Did you had any 301s in place?

Have you tried enabling clean URLs directly with:

drush vset clean_url 1

I would suggest also

perusio's picture

commenting out the global $base_url if you have set it to any value. It should work out of the box without any issue. Never seen that happen.

Disable the deslash setting in global redirect.

drush vset deslash 0

Yes, $base_url in

mesch's picture

Yes, $base_url in settings.php was commented out to begin with. Earlier I tried specifying it, but it didn't help. It is now commented out again.

I temporarily uninstalled global redirect during troubleshooting, as I saw in your README it could cause some problems. I'll reinstall when I can get this working...

I'm pretty sure it isn't a

mesch's picture

I'm pretty sure it isn't a browser problem. I've been clearing the browser cache regularly as I troubleshoot.

Yes index.php is off limits. I can only access the vhost homepage, because all other links include index.php in the url. I have to manually remove it to see other pages, or just temporarily remove "internal" from that location in the nginx vhost configuration.

For testing purposes, I did a complete replacement of my current development box nginx config with yours. The only tinkering I've done is to disable microcaching, enable/disable features based on availability in the local nginx version, and add some vhosts for drupal6 and drupal7 instances. The only 301 I'm aware of is in the "example.com.conf" file. I've tried commenting that out entirely and reloading and it doesn't solve the problem.

I tried a drupal7 instance and it works perfectly (no index.php, clean URLs work).

I see that in drupal.conf under location @drupal, fastcgi_drupal.conf is included, whereas in drupal6.conf under location = /index.php, it isn't. Could this be a source of the issue?

I tried the drush command. This did get rid of "index.php", but every url I click on now brings me to the site homepage.

I don't think so

perusio's picture

In drupal 6 the FCGI config is more standard. Therefore the fastcgi.conf file included at the http level does the work. The query string is constructed explicitly in each try_files directive.

Nginx

Group organizers

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds:

Hot content this week