How to control NGINX 'Location' directive matching order?

19,905

From the wiki:

location  = / {
  # matches the query / only.
  [ configuration A ] 
}
location  / {
  # matches any query, since all queries begin with /, but regular
  # expressions and any longer conventional blocks will be
  # matched first.
  [ configuration B ] 
}

So, this will be matched first: location ~ \.php$ {}

Even though assets are served out of location / {}

Inside the php block you also want to secure against malicious uploads before passing to fastcgi:

if ($uri ~* "^/uploads/") {
  return 404;
}

As you can see nginx works a little bit differently than you might expect.

Share:
19,905

Related videos on Youtube

leeoniya
Author by

leeoniya

Updated on June 04, 2022

Comments

  • leeoniya
    leeoniya almost 2 years

    I'm trying to optimize my 'location' directives and cannot find a good way of determining if a specific location match is even attempted. Using echo inside the location block doesn't help here.

    The NGINX ngx_http_core_module documentation is somewhat confusing.

    To use regular expressions, you must use a prefix:

    1. ~ For case sensitive matching

    2. ~* For case insensitive matching

    How the match is performed:

    1. Directives with the = prefix that match the query exactly. If found, searching stops.

    2. All remaining directives with conventional strings. If this match used the ^~ prefix, searching stops.

    3. Regular expressions, in the order they are defined in the configuration file.

    4. If #3 yielded a match, that result is used. Otherwise, the match from #2 is used.

    Number 2 here says "conventional strings" but then says it can be used with the ^~ prefix. Doesn't ~ imply a RegExp? If not, how does it determine what is an isn't a RegExp?

    Specifically, I want the following:

    1. Serve anything out of literal /assets directly. STOP SEARCH.

    2. Serve anything matching RegExp \.php$|/$ via fast-CGI STOP SEARCH.

    3. Serve everything else directly via literal /

    This way, there is only a / match attempt for non-dynamic files served from outside of assets.

    I have:

    location ^~ /assets {}      # search-terminating literal? or regex?
    location ~ \.php$|/$ {}
    location / {}               # is this match always attempted?
    

    From the document, it looks as though the actual order would be 1-3-2, always running the literal / match. Yes, this optimization won't make any difference for real performance, but I just want to clear up some ambiguity.

  • leeoniya
    leeoniya over 12 years
    i'm still unclear why the regex would be matched first. granted there are no "=" directives. next up is "All remaining directives with conventional strings". '/' is a conventional string and should be matched before any regex. the whole strings-then-regex is a hand-holding implicit optimization nginx seems to do here which makes it impossible difficult to determine the true order of evaluation. i think apache/iptables etc get it right by predictably processing in same order defined as an if/else-if/else block. without any implicit "more/less" specific rules.
  • m33lky
    m33lky over 12 years
    Right, this is definitely a bit confusing about nginx, especially nginx's if which should be used only for rewrite/return. I think they are working on simplifying this. For your situation it will work like this: 1. php regex check with a stop if it's a match 2. / for any static content.
  • leeoniya
    leeoniya over 12 years
    you are incorrect about the order. the whole point of having the /assets rule as a string first is to avoid the overhead of running the php regex on every request. in fact, i WANT to serve anything like assets/docs/example.php without passing it through FCGI. i am currently running this setup and the regex does NOT catch for example.php. it's ordered as ^~ /assets, /, ~ \.php$|/$
  • m33lky
    m33lky over 12 years
    You can ask somewhere on nginx to see if it can be done exactly like that. Also look into try_files. Using nginx over Apache is a performance boost though :)
  • m33lky
    m33lky over 12 years
    Really though I think you are wrong to worry about this performance hit. How much extra processing will it add to each static request? Compare that with php processing times and transfer times of assets that are served as separate files (instead of concatenated into one). I bet I could find many places in your application that you should be worrying about.
  • leeoniya
    leeoniya over 12 years
    yeah i know, as i noted in the OP, this isn't really about performance but about clarity in understanding the matching rules. their implicitness/complexity makes them harder to maintain, error-prone and therefore less secure