logical or in location directive with regex (multiple location using same block)

Francis Daly francis at daoine.org
Sat Nov 24 09:21:07 UTC 2018

On Fri, Nov 23, 2018 at 03:38:27PM -0800, Roger Fischer wrote:

Hi there,

> how do I best handle multiple locations that use the same code block?

Repeat the {} part with all of the config.

Nginx cares what is in the config file; it does not care how the config
file is created. Use your favourite pre-processor/macro language to
create the config, if you don't want to type the same thing twice.

> I do not want to repeat the { … } part.

Put all of the repeat-config in a separate file, and repeat the {}
part that just contains "include separate-file;".

> Is there a way to do this with logical or between regular expressions?

Probably; but you will find it to be much more readable if you don't.

> The first variation is that sometimes there are query parameters, and sometimes there are not. The second variation is that there are multiple suffixes that should match the same block.

"location" matching does not consider query parameters. It stops before
the first ? or # in the uri.

> As an example, the following locations all should have the same behaviour:
> * /variable-part.gif
> * /variable-part.gif?variable-query-parameters
> * /variable-part.png
> * /variable-part.png?variable-query-parameters
> The equivalent regular expressions I am using are:
> * ~* \.gif$
> * ~* \.gif\?
> * ~* \.png$
> * ~* \.png\?
> I know, I can combine the different types:
> * ~* \.(gif|png)$
> * ~* \.(gif|png)\?

The ones with "\?" will not match the requests above.

> But I don’t know how to combine the end-of-uri with the followed-by-query-parameters into a single regex.

You don't need to.

(You *can* match end-of-string or following-character by using regex
alternation with |. You just do not need to in this particular case.)

> Lastly, I also have locations with a quite different pattern that has the same code block.
> So, what I would like is something like this:
> location  (  ~* \.(gif|png)$  |  ~* \.(gif|png)\?  |  = /xyz ) { … }
> “|” represents a logical or.
> Is there a way to do this?


You can probably build one probably-very-complex regex to include
everything you want and to exclude everything you don't want; but you'll
be much happier in 6 months when you need to change something, if your
config is human-readable.

(The full efficiency effects of the nginx "=" match can't be achieved
with a regex match.)

> BTW, should the regular expression be in quotes (single or double)?

Only if it needs to be. (Which probably means "if it includes {".)

"nginx -t" will probably tell you if you got it wrong.

And it should be generally straightforward to test. Something like

  location / { return 200 "no match\n"; }
  location ~ x { return 200 "match no-quotes\n"; }
  location ~ "y" { return 200 "match double-quotes\n"; }
  location ~ 'z' { return 200 "match single-quotes\n"; }

and then make requests that include x, y, and z, and see if they are
each processed in the location that you expect they should be.

Good luck with it,

Francis Daly        francis at daoine.org

More information about the nginx mailing list