Nested locations blocks in NGINX configuration
If you’re anything like me, you’ve often found yourself looking at the NGINX documentation (you know, just for fun) and finding the following:
locationblocks can be nested, with some exceptions mentioned below
And you’ve thought to yourself, “Wow, that’s so non-specific. What does nesting a location block actually mean? Why would I want to do it?”
Well, I’ve investigated the nginx config at length and can offer some insights from my findings. You can always take a look at the NGINX documentation if you need a refresher on how NGINX config location blocks work.
Four types of NGINX config locations can be defined, and I’ll call them like so:
- Exact-match (=-type) locations
- Plain config locations
- Strong prefix config locations
- Regex config locations
The first three are alike in that they’re all prefix-type NGINX config locations. They all have to match the start of the requested Uniform Resource Identifier (URI). So
location /foo will only ever match a request for
http://some.site/foo/bar/, it can’t match
http://some.site/bar/foo/, even though
/foo is in there somewhere. Although RegEx locations are treated a bit differently, as we’ll see later in this article so stay tuned.
Prefix NGINX config locations
When NGINX is handling a request, it will try to figure out which NGINX config location block applies—only one location can apply. To do that, it scans through the NGINX config file from top to bottom—well, building the file is another topic, too. Just think of it as an NGINX config file looking for prefix-type locations, for now. Whenever it finds a location that matches the current request, it checks to see if this location is a longer match than the last one it saw. If it is, NGINX remembers it. If the location matches exactly and is an
=-type, then it terminates its search and immediately just uses that location block right away without even consulting RegEx-type locations. Notably,
=-type locations can’t have locations nested in them at all, and NGINX will treat it as an error if you try.
If there are any prefix-type locations nested within the newly-remembered block, it considers those at this time, just as if they were defined at the top level.
RegEx NGINX config locations
If NGINX gets to the end of the NGINX config file without having matched an
=-location, then it will have a record of the longest prefix-type location that matches this request. It will then proceed to test any RegEx-type locations, starting with the locations defined inside the prefix-type location that matched. The first time one of these matches, it stops looking and simply uses that NGINX config location block. When it gets to the end of the prefix-type location with no match, it keeps looking at the start of the NGINX config file.
You can’t have a prefix-type location block nested within a RegEx-type location block at all, and NGINX will call this out as an error if you try.
Finally, there’s one last exception to what happens after prefix NGINX config locations are finished being searched. If the best prefix-type location block has the strong-prefix modifier (
^~), then it won’t check any RegEx locations at all, except for nested RegEx locations.
Share your insights on NGINX config locations with Upsun
Hopefully, that was helpful for my fellow NGINX investigators out there. I jumped down the rabbit hole of NGINX config intricacies a little while ago and found it surprisingly difficult to find a complete answer so I wanted to share what I did find after taking a deep dive. Have you ever taken on your own NGINX investigation? What did you find?
Share, chat, debate–let us know your thoughts and findings on Discord.