Tutorial for using Nginx in front of Apache and mod_php, to serve static files?

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

Hello all! I've been looking through this group's discussions, and am very thankful for all the help and advice. Here's my situation: I recently moved from shared hosting to a VPS (Linode.com). I'm a relatively competent with html/css/php, etc., but am fairly noobish when it comes to the whole server side of things. I can find information, and follow and adapt tutorials, but have a hard time knowing how to hack things out from scratch.

So I've set up my VPS running Ubuntu 9.10 (Karmic) with Apache2, mysql, and php, and have my vhosts up and running with drupal. What I want to do now is set Nginx up as a static file server, leaving dynamic content to Apache and mod_php. I just haven't been able to find a comprehensive tutorial for how to do that, taking drupal into account (specifially, image_cache and boost). Basically what I'm looking for is this:

http://www.lullabot.com/articles/using-lighttpd-static-file-server

But geared towards Nginx instead of Lighttpd (because of the memory leak issues I've read about). Can anyone point me towards some good resources to help me get this set up?

Thanks a ton!

Comments

Nginx proxy to Apache

davidwhthomas's picture

I have nginx set up to proxy all requests through to apache.

It's solved a load issue where apache was exhausting it's connections and memory.

Nginx is managing all the client requests and working really well.

I'm also keen to figure out how to get nginx to serve the static cache in this context.

In the spirit of open-source, here's the nginx.conf and sites-enabled conf in use:

Nginx listens on port 81 and proxies to Apache on port 80. The load balancer forwards http traffic to port 81 for nginx.

/etc/nginx/nginx.conf

user www-data;
worker_processes  1;
worker_rlimit_nofile 8192;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
    worker_connections  4096;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    access_log  off;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;
    tcp_nodelay        on;

    gzip  on;
    gzip_types application/javascript application/x-javascript text/css text/xml application/xml;

    server_tokens off;

    client_max_body_size 8M;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;

}

/etc/nginx/sites-enabled/00-nginx-default

server {
    listen 81 default;

    access_log  /var/log/nginx/default.access.log;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://localhost:80;
    }
}

You also need to

sudo apt-get install libapache2-mod-rpaf

So apache uses the x-forward-for ip address

If someone could chime in on how to throw boost rules into the mix, that'd be great.

cheers,

DT

P.S note, there should be asterisk characters in

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
Drupal stripped them out in my first post so I escaped them '\' and all good.

I'm not sure how that works

brianmercer's picture

I'm not sure how that works with nginx listening on port 81 and apache on port 80. It seems like nginx would not get any traffic with that setup.

Web traffic is coming in on port 80. Your front end reverse proxy/load balancer/static web server (varnish /haproxy/nginx) listens for port 80 traffic and serves what it should and then directs some traffic to a backend listening on some arbitrary port (though people usually use 81 or 8080 as a convention).

There's a loadbalancer

davidwhthomas's picture

Like I said, there's a loadbalancer on the firewall box that forwards http traffic to port 81 on the webservers ( where nginx is running in front of apache )

Sorry, I missed that.

brianmercer's picture

Sorry, I missed that. Thanks.

no problem, it could be done

davidwhthomas's picture

no problem, it could be done listening on port 80 with apache on another port but for this setup we've got a bunch of existing sites / vhosts so was easier to leave them on 80 and put nginx on 81.

Imgacache?

ajayg's picture

How you serve images plain or through imagecache? If imagecache you would need nginx with php, correct?

I a looking for some way to serve images from cached imagecache directoy and if it can't find a cached image then forward the request to apache so imagecache module can cache it.

The exact syntax will vary

brianmercer's picture

The exact syntax will vary depending on your config file, but you have it right. A separate location block is defined for /files/imagecache and 404 errors are sent to the php backend instead of nginx just replying with a generic 404 file not found response.

There's almost no difference

brianmercer's picture

There's almost no difference between setting up nginx with fastcgi and setting up nginx with apache.

Start with Omega8cc's nginx setup at

http://github.com/omega8cc/nginx-for-drupal/blob/master/nginx.conf

which is configured to serve static files and boost pages from nginx.

Then replace

          fastcgi_pass 127.0.0.1:9000; ### php-fpm listening on port 9000
          fastcgi_index index.php;

with
        proxy_set_header    X-Real-IP  $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header    Host $http_host;
        proxy_redirect      off;
        proxy_pass          http://127.0.0.1:8080;

and you're 98% there.

Thanks, that conf is

davidwhthomas's picture

Thanks, that conf is massive! I'm liking the working simple conf from above at the mo, but interesting nonetheless.

Needs a bit of tuning for this server setup.

I set it up and get an error on try_files

5565#0: unknown directive "try_files" in /etc/nginx/nginx.conf:109

Maybe the directive isn't available in this version... ( 0.6.32-3ubuntu1.1 )

*edit: yeah, it requires "Latest 0.8.x nginx build - see nginx-install.txt" ( http://github.com/omega8cc/nginx-for-drupal/blob/master/README )

back to the drawing board...

*edit: will try using an if ( -f $file ) { ... } block instead for the earlier version

Yeah. Try_files was

brianmercer's picture

Yeah. Try_files was introduced somewhere around 0.7.21. It looks like you're using the Intrepid repo version.

I'd recommend adding Jeff Waugh's PPA.

https://launchpad.net/~jdub/+archive/ppa

That'd get you to 0.7.62, the current "stable" version and he updates it pretty often.

It's compiled for Hardy, but I've used his versions with later Ubuntu releases.

Debian Lenny

davidwhthomas's picture

Thanks, you're correct I was testing on Intrepid, though this config is actually for Debian Lenny servers.

They need to use applications from the standard repo, mainly for stability.

Will see if I can come up with a suitable conf, if so will post here.

cheers,

DT

Thanks, that conf is

yhager's picture

Thanks, that conf is massive!

I took a go at writing a simple config at http://github.com/yhager/nginx_drupal - but it uses try_files directive as well.
There are ways around that, but really nginx with try_files is rather stable - so I suggest you try and find a good nginx release for your distro than trying to work around the missing directive.

In your conf, at first I used

jcisio's picture

In your conf, at first I used the same approach:

if ($http_cookie ~ "DRUPAL_UID" ) {
    return 405;
}
...
error_page 405 = @drupal;

and in @drupal there is a reverse proxy directive. But that didn't work when redirect (drupal_goto). In fact, when the browser sees 405 error, it ignores the Location header. So I replace "return 405" by "proxy...;break" and it works!

That part is aimed ad

yhager's picture

That part is aimed ad bypassing boost files. When the user has a Drupal cookie, nginx sends a 405 internally which goes to @drupal, which sends the request to fastcgi engine for handling, which means it runs Drupal for this request.

The 405 is internal to nginx and should not go to the browser.

Can you share the full patch you made to the config? I am not sure I understood what you did and where.

The main code server {   

jcisio's picture

The main code

server {
    listen 80;
    server_name www.thongtincongnghe.com ttcn.mobi;
    root /home/ttcn/public_html;
    error_page 405 @proxy;
    location ~ .(gif|jpg|jpeg|png|js|css)$ {
        try_files $uri @proxy;
    }

    location / {
        if ( $request_method !~ ^(GET|HEAD)$ ) {
#            return 405;
proxy_pass http://127.0.0.1:8080;
break;
        }
        if ($http_cookie ~ "DRUPAL_UID") {
#            return 405;
proxy_pass http://127.0.0.1:8080;
break;
        }
        try_files /cache/normal/$host${uri}$args.html /cache/perm/$host${uri}.css @proxy;
    }
    location @proxy {
        proxy_pass http://127.0.0.1:8080;
        proxy_cache cache;
        proxy_cache_valid  200 302  60m;
        proxy_cache_valid  404      1m;
    }
}

If I left the "return 405", Drupal pages aren't redirected after form submission. And in Firebug, I can see the status code is 405 instead of 200.

In the 4th line of your

yhager's picture

In the 4th line of your config, try

  error_page 405 = @proxy

notice the equal sign.
See http://wiki.nginx.org/NginxHttpCoreModule#error_page

Indeed!

jcisio's picture

Indeed. Thanks, yhager. How I know I have to learn copy/paste.

No, I said too soon. With

jcisio's picture

No, I said too soon. With that fix user can't login (with password or with one-time login token). Replace "return 405" by "proxy..." fixes that. It's on a production server so I can't test now, but I'll be back!

Thanks a lot davidwhthomas

jordanmagnuson's picture

Thanks a lot davidwhthomas and brianmercer!

Nginx

Group organizers

Group notifications

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

Hot content this week