Try_files, POST, and redirecting requests to Passenger

The application I’m working on (CMS) has a few interesting requirements:

  • Custom user domains
  • Very heavily page cached.
  • Any page can be POSTed to (page has a form on it)

In Apache, this was easily handled. If GET, then look in the cache, then
fall to Passenger. Otherwise, just go straight to Passenger.

I have been unable to get nginx working for my needs and am wondering if
anyone else has any insight into how to solve this problem.

Basically what I want is the following (but can’t because try_files
can’t be in an if):

location / {
if ($request_method ~* ^(GET|HEAD)$) {
try_files /cache/$domain/$uri
/cache/$domain/$uri.html
/cache/$domain/$uri/index.html
/maintenance.html
@passenger;
break;
}

try_files /maintenance.html @passenger;

}

location @passenger {
passenger_enabled on;
}

I initially had the idea that try_files was more of a switch-statement,
and tried to do something like:

try_files @cache maintenance.html @passenger;

then in @cache simply break if the request is not a GET, but that
obviously only ever went to @passenger, because @cache wasn’t a real
file on the system.

I’ve tried the error_page 405 = @passenger route, but that has a very
severe problem in that it turns my POST request into a GET, and I was
unable to find out how to stop that. Is there a way?

I’ve also tried doing an internal redirect to a different location
block, something like:

location /post {
internal;
passenger_enabled on;
}

but then I end up with $uris that have /post/(uri i want) and don’t know
how to tell nginx to ignore /post when sending down to passenger. Would
also appreciate ideas here if there are any.

Any other suggestions? I’m almost to resorting to a number of if
statements and really don’t want to end up there.

I am using nginx release: 1.2.6 on ubuntu 12.04 and Passenger
Enterprise.

Thanks

Jason

On 8 January 2013 23:13, Jason R. [email protected] wrote:

if ($request_method ~* ^(GET|HEAD)$) {

location @passenger {
passenger_enabled on;
}

Does try_files accept a variable generated from a map based on the
$request_method variable, perhaps?

That’s the way I usually avoid ifs.

Jonathan

Jonathan M. // Oxford, London, UK
http://www.jpluscplusm.com/contact.html

On 9 Jan 2013 00h13 CET, [email protected] wrote:

I have been unable to get nginx working for my needs and am
/cache/$domain/$uri/index.html
}
You’re mixing different things. break is a rewrite phase
directive, like if. So they’re executed well before try_files and the
content phase handlers.

You should use the map directive.

At the http level:

map $request_method $idempotent {
default 0;
GET 1;
HEAD 1;
}

then at the server level (vhost config):

location / {

error_page 418 = @idempotent;

if ($idempotent) {
    return 418;
}

try_files /cache/$domain/$uri /cache/$domain/$uri.html
/cache/$domain/$uri/index.html /maintenance.html @passenger;

}

location @idempotent {
try_files /maintenance.html @passenger;
}

location @passenger {
passenger_enabled on;
}

Try it.
— appa

On 9 Jan 2013 15h22 CET, [email protected] wrote:

try_files /maintenance.html @passenger;
}

I never knew about the map directive, that’s quite interesting. One
question though, will this make sure that a POST that hits the
error_page 418 stays a POST when it goes through the @idempotent
location?

Perhaps I misunderstood. The way it is configured above is such that
the @idempotent location will only be used for GET and HEAD requests.
All other requests are handled by the / location using the lenghty
try_files.

I thought that was your desired config.

Thanks for the info!

You’re welcome.

— appa

“António P. P. Almeida” [email protected] wrote in post #1091574:

On 9 Jan 2013 00h13 CET, [email protected] wrote:

error_page 418 = @idempotent;

if ($idempotent) {
    return 418;
}

location @idempotent {
try_files /maintenance.html @passenger;
}

I never knew about the map directive, that’s quite interesting. One
question though, will this make sure that a POST that hits the
error_page 418 stays a POST when it goes through the @idempotent
location?

Thanks for the info!

Jason

On 9 Jan 2013 20h39 CET, [email protected] wrote:

cannot
/$cache_path/$cache_host/$uri.html
/$cache_path/$cache_host/$uri/index.html
/maintenance.html
@passenger;

This way there’s no possible way a valid file is found when
POST-ing. This was the simplest solution we could come up with at
this time.

Thanks for everyone’s help.

It’s even simpler then. No need for map.

location / {
error_page 418 = @post;

if ($request_method = POST) {
    return 418;
}

try_files /cache/$domain/$uri /cache/$domain/$uri.html
/cache/$domain/$uri/index.html /maintenance.html @passenger;

}

location @post {
try_files /maintenance.html @passenger;
}

location @passenger {
passenger_enabled on;
}

— appa

“António P. P. Almeida” [email protected] wrote in post #1091605:

On 9 Jan 2013 15h22 CET, [email protected] wrote:

try_files /maintenance.html @passenger;
}

I never knew about the map directive, that’s quite interesting. One
question though, will this make sure that a POST that hits the
error_page 418 stays a POST when it goes through the @idempotent
location?

Perhaps I misunderstood. The way it is configured above is such that
the @idempotent location will only be used for GET and HEAD requests.
All other requests are handled by the / location using the lenghty
try_files.

I thought that was your desired config.

Thanks for the info!

You’re welcome.

— appa

Sorry if I mispoke then, what I want is the exact opposte because POST
should never hit a cache file.

We ended up going a slightly different route in that we hack the cache
file location according to the request type (we have $cache_host because
there’s some other processing we do, not relevant here):

Set cache_path to a non-existant directory so try_files fails if we

cannot

serve the request from the cache.

set $cache_path “no-cache”;
set $cache_host $host;

if ($request_method ~* ^(GET|HEAD)$) {
set $cache_path “cache”;
}

try_files
/$cache_path/$cache_host/$uri
/$cache_path/$cache_host/$uri.html
/$cache_path/$cache_host/$uri/index.html
/maintenance.html
@passenger;

This way there’s no possible way a valid file is found when POST-ing.
This was the simplest solution we could come up with at this time.

Thanks for everyone’s help.

Jason

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs