Nested location block for merging config returns 404?

I want a location to proxy to another service, and need to add an extra
header for certain file types, but when trying to merge the
configuration
with a nested location instead of duplicating nginx instead returns a
404.

For example, this configuration works:

location ~ /(dir1/)?dir2/ {
add_header X-My-Header value1;
proxy_pass http://myproxy;
}

location ~ /(dir1/)?dir2/.*.(txt|css) {
add_header X-My-Static value2;
add_header X-My-Header value1;
proxy_pass http://myproxy;
}

Passing valid URLs to the above config works perfectly, and I’ll get the
extra header set if it’s a txt or css file (examples for the sake of
argument). However, what I want to accomplish is to merge these two
blocks
into one nested location block to save on the duplication, however when
I do
that I just get a 404 returned for the previously workings URLs:

location ~ /(dir1/)?dir2/ {
location .(txt|css) {
add_header X-My-Static value2;
}
add_header X-My-Header value1;
proxy_pass http://myproxy;
}

Can location blocks actually be nested in this way? I’m wondering if the
404
is because it’s only parsing the specific nested block, and doesn’t
fallback
onto the remaining config underneath (and therefore never gets sent to
the
proxy, and it’s nginx returning a 404 which would be expected for that
URL).

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,246655,246655#msg-246655

On 21 January 2014 13:29, WheresWardy [email protected] wrote:

Can location blocks actually be nested in this way?
I believe they can be, staticprefix-inside-regex as you’ve done. The
norm is to have regex-inside-staticprefix, and it’s usually done for
performance reasons. I suggest you’ve made an error in not marking
your inner location as a regex, however, and this may be causing your
404s.

Jonathan

I don’t think it’s a regex issue, because if I add an additional
proxy_pass
inside the nested location block, I then get a valid request.
Additionally,
any headers set inside the outer location block don’t appear, but then
if I
duplicate them inside the nested location block, they then appear (just
the
once).

This basically means I’d have to duplicate anything in the outer
location
block in the nested one, which kind of defeats the purpose, and it’s
cleaner
to have the separate same-level config.

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,246655,246657#msg-246657

Your line

location .(txt|css) {

looks like a regex, but you’re not telling nginx it /is/ a regex. I
wouldn’t expect anything to work until you fix that.

Apologies, that was a typo during simplification of my config. I do
indeed
have a ~ in my nested location block, and it’s definitely matching
correctly.

Everything else you’ve specified seems to fit my observed behaviour, so
think it’s just that my use case doesn’t fit with the inheritance rules
as
they stand. Thanks for your help!

Posted at Nginx Forum:
http://forum.nginx.org/read.php?2,246655,246660#msg-246660

On 21 January 2014 13:40, WheresWardy [email protected] wrote:

I don’t think it’s a regex issue, because if I add an additional proxy_pass
inside the nested location block, I then get a valid request. Additionally,
any headers set inside the outer location block don’t appear, but then if I
duplicate them inside the nested location block, they then appear (just the
once).

You may have multiple things to solve here.

Your line

location .(txt|css) {

looks like a regex, but you’re not telling nginx it /is/ a regex. I
wouldn’t expect anything to work until you fix that.

Secondly, the inheritance behaviours you’re seeing are as I’d expect:

  1. I don’t believe proxy_pass statements are inherited, both as you’re
    seeing from outer-location{} to inner-location{} but also from, for
    example, server{} to location{}. You need to define each proxy_pass
    where you want it to be used.

  2. add_header (again, in my understanding) is a slightly different
    beast: it is inherited, outer to inner, but only if you don’t
    re-use it in the inner location. As soon as you use it inside the
    inner location, all the inherited add_header directives are forgotten.
    Again - that’s what I /think/ is the case - I welcome others to
    correct me if I’m misremembering …

Cheers,
Jonathan

On Tuesday 21 January 2014 08:29:18 WheresWardy wrote:

that I just get a 404 returned for the previously workings URLs:
is because it’s only parsing the specific nested block, and doesn’t fallback
onto the remaining config underneath (and therefore never gets sent to the
proxy, and it’s nginx returning a 404 which would be expected for that URL).
[…]

Yes, they can. But, please note that the proxy_pass directive is not
inherited, and you should duplicate it in your nested location block.

There is a good article on the topic:
http://blog.martinfjordvald.com/2012/08/understanding-the-nginx-configuration-inheritance-model/

wbr, Valentin V. Bartenev

On 21 January 2014 13:59, WheresWardy [email protected] wrote:

Everything else you’ve specified seems to fit my observed behaviour, so
think it’s just that my use case doesn’t fit with the inheritance rules as
they stand. Thanks for your help!

No problem. You could look at using a map to achieve the config
deduplication you’re aiming for. Something like this (typed, but not
tested or syntax-checked!)


http {
map $uri $map_output {
default “”;
~ .txt “value2”;
~ .css “value2”;
}
server {
location ~ /(dir1/)?dir2/ {
add_header X-My-Header value1;
add_header X-My-Static $map_output;
proxy_pass http://myproxy;
}
}
}