Improved nginx.conf for Ruby On Rails


#1

I’ve been trying to improve the standard nginx.conf for Ruby On Rails
(http://wiki.codemongers.com/NginxRubyonRailsMongrel) with the help of
Maxim D., and so far this is what we got:

user www www;

worker_processes 5;

events { worker_connections 1024; }

http {

include /usr/local/etc/nginx/mime.types;

default_type application/octet-stream;

sendfile on;

upstream mongrel {

server 127.0.0.1:5000;

server 127.0.0.1:5001;

server 127.0.0.1:5002;

}

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 false;

server {

listen 80;

server_name mysite.com www.mysite.com;

root /usr/local/www/mysite/public;

location / {

  error_page 404 = @fallback;

}

location @fallback {

  proxy_pass http://mongrel;

  proxy_intercept_errors on;

  recursive_error_pages on;

  error_page 500 502 503 504 /500.html;

}

location = /500.html {}

}

}

Anybody care to chip in?


#2

http://gist.github.com/15078

Special tweaks include enabling the first request of rails cached
stylesheets to be served by the mongrel, but all future requests
served by the web server. Far Futures expires. Support for 503’ing and
displaying a maintenance page.

A lot of this was taken from Ezra Z.'s post last year.
http://brainspl.at/articles/2007/01/03/new-nginx-conf-with-optimizations


#3

On Mon, Oct 6, 2008 at 7:07 PM, W. Andrew Loe III removed_email_address@domain.invalid
wrote:

http://gist.github.com/15078

Special tweaks include enabling the first request of rails cached
stylesheets to be served by the mongrel, but all future requests
served by the web server. Far Futures expires. Support for 503’ing and
displaying a maintenance page.

A lot of this was taken from Ezra Z.'s post last year.
http://brainspl.at/articles/2007/01/03/new-nginx-conf-with-optimizations

http://brainspl.at/nginx.conf.txt is pretty much the same as
http://wiki.codemongers.com/NginxRubyonRailsMongrel. The whole point
of an improved nginx.conf would be to get rid of those ifs (bad
practice from what I hear) and all the other stuff we don’t need.
Perfection is achieved, not when there’s nothing left to add, but when
there’s nothing left to take away.


#4

Hello!

On Mon, Oct 06, 2008 at 09:33:36PM +0200, Thomas wrote:

Who told you the ifs are bad practices? They are here to enable
Nginx to directly serve static files.

Me, Igor and many others. They do unneeded work, including
unneeded syscalls. Doing an open() in ngx_http_static_module is
just enough for anything in this particular case.

By the way in your case, mongrel will be serving static files,
and this is really bad!

No. All files that exists under root will be served by nginx
itself. Only non-existent urls will be proxied to backend.

Take a look at:

 location / {
     error_page  404  = @fallback;
 }

This will instruct nginx to serve static files and installs a
handler for 404 Not Found errors. I.e. if file is here - nginx
will just serve it to client. If it’s not here - it will run
error_page handler instead.

Normally you write in error_page something like

 error_page  404  /errors/404.html;

to serve “pretty” errors to clients. But it can do much more. In
this particular case we use

 error_page  404 = @fallback;
  • ‘=’ to make sure resulting page will be served with response code
    returned by handler itself, not 404

  • @fallback instead of uri to serve request within context of
    named location @fallback

In it’s turn, within @fallback location request will be proxied to
backend. And this will happen only if there is no static file
available.

Some notes:

  1. Named locations are relatively new beasts. They appeared in
    nginx 0.6.6, and there are known issues with them in 0.6.32
    (notably with POST requests, fixed in 0.7.12). I wouldn’t
    recommend using the config in question with stable branch for now
  • at least if you have POST requests. Try 0.7.* instead. :slight_smile:
  1. As far as I see, the config in question differs from the
    http://wiki.codemongers.com/NginxRubyonRailsMongrel in some
    aspects of it’s behaviour. E.g. the latter one will serve /blah
    request as static if there is /blah.html. If this behaviour is
    really desired - config should be modified appropriately. I don’t
    think that it’s a good practice though.

  2. I’ve been mentioned in the original post, but in fact I’ve just
    explained how standard fallback technique work and fixed some
    obvious errors. Don’t blame on me if it doesn’t work. :slight_smile:

Maxim D.


#5

Who told you the ifs are bad practices? They are here to enable Nginx
to directly serve static files. By the way in your case, mongrel will
be serving static files, and this is really bad!


#6

On Oct 6, 2008, at 2:03 PM, Maxim D. wrote:

  1. As far as I see, the config in question differs from the http://wiki.codemongers.com/NginxRubyonRailsMongrel
    in some aspects of it’s behaviour. E.g. the latter one will serve /
    blah request as static if there is /blah.html. If this behaviour is
    really desired - config should be modified appropriately. I don’t
    think that it’s a good practice though.

I agree with getting rid of the if’s as much as possible. But
breaking this #2 rule will break every rails application in existence
that uses page caching. This rule must be supported or else you
break everyone’s apps and expectations and cannot call this a true
rails nginx config.

Other then that getting rid of the if’s is a good thing.

Cheers-
-Ezra


#7

No. All files that exists under root will be served by nginx itself. Only
non-existent urls will be proxied to backend.

Yeah I forgot to mention that the if statements were for rails apps
that use page caching.

@Andrew Loe: be very careful with your config file, I noticed you
defined server_name _; this can be dangerous depending on how your app
works. I have posted something about a potential security hole I have
more or less discovered this WE.


#8

Hi Maxim,

On 6 Oct 2008, at 22:03, Maxim D. wrote:

  1. Named locations are relatively new beasts. They appeared in
    nginx 0.6.6, and there are known issues with them in 0.6.32 (notably
    with POST requests, fixed in 0.7.12). I wouldn’t recommend using
    the config in question with stable branch for now - at least if you
    have POST requests. Try 0.7.* instead. :slight_smile:

Igor S posted a couple of 0.6.x patches in a thread called static POST
in mid-August this year which made named locations and POST work as
expected for me in 0.6.32. We have it in production and it doesn’t
appear to have caused us any problems as yet. Igor said he would merge
the patch for 0.6.33.

Best wishes
Igor


#9

On Mon, Oct 6, 2008 at 7:07 PM, W. Andrew Loe III removed_email_address@domain.invalid
wrote:

http://gist.github.com/15078

Special tweaks include enabling the first request of rails cached
stylesheets to be served by the mongrel, but all future requests
served by the web server. Far Futures expires. Support for 503’ing and
displaying a maintenance page.

A lot of this was taken from Ezra Z.'s post last year.
http://brainspl.at/articles/2007/01/03/new-nginx-conf-with-optimizations

Just to add to Ezra’s config file, checkout a lengthy post at
http://www.opensourcery.co.za/2008/05/15/nginx-reading-the-fine-print/
on some fine print for the proxy_next_upstream directive. This is
probably only applicable to Rails apps that have long running
requests, like intensive reports or integration into slow third party
systems…

Best


#10
  1. Needs some options for adding expires headers to static assets
  2. I really like my config files templated as far as possible, ie chuck
    as much of the static stuff in a fixed file and make the main file just
    include it all in. If we could use variable names in a couple of extra
    places then the whole file could be templated…
  3. Are you sure it handles rails page caching? Care to explain how?

Ed W


#11

Nah, actually my config doesn’t work at all. Maxim D. had no idea
it was for Rails, so I’m back to square one.

Unless y’all got something better than the brainspl.at one?


#12

Please share! We use wildcard DNS in our application so I need the
server listening to all hosts.


#13

I think mine are similar - the main thing I did was to tease as much as
possible into separate files and then include them back together again

If more of the log files and mongrel stuff could be templated then you
could do the whole thing with a simple templated include… Oh well

Yes, do share. I’ve been trying to find some sort of middle ground,
http://pastie.org/293795, suggestions are always welcome!


#14

server {
listen 80;
server_name your.domain *.your.domain;
}

Cheers

Dave