Setting expires header bypasses app server

Hi all,

I have nginx proxying to a couple of thin servers.

For a request like /javascripts/foo.js a controller called ‘javascripts’
generates some dynamic js and caches it to
$document_root/javascripts/foo.js.

The relevant part of the nginx config file:

root /apps/foo-app/current/public;

location / {
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;
proxy_max_temp_file_size 0;

if (-f $request_filename) {
  break;
}

if (!-f $request_filename) {
  proxy_pass http://thins;
  break;
}

location ~* \.(js|css|jpg|jpeg|gif|png)$ {
  if (-f $request_filename) {
    expires      max;
    break;
  }
}

}

When request /javascripts/foo.js on the production app (hitting nginx) a
404 is returned directly instead if the request being passed to the app
servers. I would expext the request to be passed to the app servers as
the file is not on the filesystem. Why doesn’t the !-f $request_filename
condition (lines 15-18) apply?

If I remove the last portion of the nginx config file (the one which
adds an expires header to static files) all works as expected.

Any idea what might be wrong?

Best,
Nickolay

Posted at Nginx Forum: Setting expires header bypasses app server

On Wed, Apr 1, 2009 at 3:34 AM, nmk [email protected] wrote:

  }

 }

When request /javascripts/foo.js on the production app (hitting nginx) a 404 is returned directly instead if the request being passed to the app servers. I would expext the request to be passed to the app servers as the file is not on the filesystem. Why doesn’t the !-f $request_filename condition (lines 15-18) apply?

If I remove the last portion of the nginx config file (the one which adds an expires header to static files) all works as expected.

Any idea what might be wrong?

It’s because it is matching that regexp first.

You could do your if (-f ) check inside of there and it would probably
work, but that’s kind of messy. I’m sure Igor can post and give you a
much cleaner way to do the entire thing. Location blocks confuse the
hell out of me sometimes.

That’s because it is hitting the location ~*
.(js|css|jpg|jpeg|gif|png)$ { first

try this (until Igor comes up with something better)

location ~* .(js|css|jpg|jpeg|gif|png)$ {
if (!-f $request_filename) {
proxy_pass http://thins;
break;
}
if (-f $request_filename) {
expires max;
break;
}
}

I don’t know if the braces got aligned properly but that general idea.

It’s because it is matching that regexp first.

You could do your if (-f ) check inside of there
and it would probably
work, but that’s kind of messy.

I am doing a -f check in the location. Still doesn’t work as I expect it
to.

Could you provide an example please?

I’m sure Igor can
post and give you a
much cleaner way to do the entire thing.

I hope so. :slight_smile: I still haven’t got it working.

Best,
Nickolay

Posted at Nginx Forum: Re: Setting expires header bypasses app server

On Thu, 2009-04-02 at 11:20 -0700, Michael S. wrote:

}
if (-f $request_filename) {
expires max;
break;
}
}

You probably don’t need a separate test to set the Expires header:

location ~* .(js|css|jpg|jpeg|gif|png)$ {
expires max;
if (!-f $request_filename) {
proxy_pass http://thins;
}
}

The backend should supply its own Expires header that overrides the
Nginx one (or perhaps Nginx doesn’t set Expires for proxied requests -
I haven’t specifically tested to see which it is). In any case, this
has worked fine whenever I’ve used it (you can check the wiki headers,
which has expires 30d set on / before passing to mediawiki).

And I’d probably use something like this in any case (I’ve never used
try_files, but this looks right):

location ~* .(js|css|jpg|jpeg|gif|png)$ {
expires max;
try_files $request_filename @thins;
}

location @thins {
proxy_pass http://thins;
}

And as a side note, getting rid of the regex would be a lot more
efficient. I’d consider making a special location for these files so
you could avoid the need for that.

Cliff