Nginx does not sort location blocks alphabetically by default; it selects the most specific match based on strict prefix, regex priority, and general prefix rules. If your configuration appears to ignore alphabetic order for non-matching URLs, it is likely due to how Nginx prioritizes exact matches over general prefixes or how regex locations are evaluated. Understanding these precedence rules is essential for correct routing behavior.
Understanding Nginx Location Precedence
The core misunderstanding often stems from assuming that the order of blocks in the
nginx.conf file determines execution flow. In reality, Nginx evaluates location blocks based on specificity, not insertion order. The hierarchy is as follows:
- Exact Match (
=): Highest priority. Matches the URI exactly.
- Prefix Match with ^~ modifier: Stops regex search if matched. High priority for static assets.
- Regex Locations (
~ or ~*): Evaluated in the order they appear in the configuration file. First match wins.
- General Prefix Match: Longest prefix wins. If two prefixes match, the longer one is chosen regardless of file order.
When a URL does not match any request handler explicitly, Nginx falls back to the default server block or the first defined location. This fallback behavior can seem like "alphabetic order" issues if you expect a specific catch-all block to trigger before another, but Nginx strictly adheres to the longest-prefix rule for standard locations.
The Role of Regex Order
Unlike prefix locations, regex locations
~ and
~* are processed in the order they appear in the config file. If you have multiple regex blocks, the first one that matches the URI is used. This is a common source of confusion when developers expect alphabetical sorting to apply here as well. For example:
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm.sock;
}
location ~* \.(jpg|jpeg|png)$ {
expires 30d;
}
If a request comes for
image.jpg, the second block matches. However, if you had a more complex regex earlier in the file that also matched, it would take precedence because it appeared first. This linear evaluation is distinct from the longest-prefix logic used for static paths.
Why Non-Matching URLs Behave Unexpectedly
When a URL does not match any specific location block, Nginx uses the default server context. If you have multiple server blocks, the one matching the
server_name directive is selected. Within that server block, if no location matches, Nginx serves content from the
root or
index directive specified in the server block itself.
This behavior can mimic an ordering issue. For instance, if you have a generic location block at the end of your config intended to handle all remaining requests, but an earlier prefix block catches part of the path, the later block never executes. This is not an error in alphabetic sorting but a result of the longest-prefix match rule.
To debug this, check which location block is actually handling the request using the
-v flag in Nginx logs or by enabling debug logging. You can also use tools like
nginx -T to view the compiled configuration and see how Nginx has resolved the precedence internally.
Common Misconfigurations
One frequent mistake is placing a broad prefix location before a more specific one, expecting the broader one to act as a fallback. Since Nginx picks the longest matching prefix, a block like
location /api/ will always win over
location / for any URI starting with
/api/, regardless of their order in the file.
Another issue arises with trailing slashes.
location /path and
location /path/ are treated differently. Requests to
/path may not match
/path/ depending on how redirects are configured, leading to unexpected 404s or redirect loops. Always ensure your location directives account for potential trailing slash variations.
For deeper insights into resolving similar configuration conflicts, you might find
Nginx Configuration Issue helpful. It covers broader structural problems that often manifest as routing errors.
Solving the Routing Priority Problem
To ensure your desired behavior, explicitly define the precedence using modifiers. Use
= for exact matches,
^~ to prevent regex checks after a prefix match, and carefully order your regex blocks. If you need a true fallback, place a generic
location / block at the end of your server context, but be aware it will only catch URIs that do not match any longer prefix.
Consider restructuring your configuration to group related locations. Use comments to document why certain blocks are ordered as they are, especially for regex locations. This improves maintainability and makes debugging easier when new routes are added.
Additionally, test your configuration changes using
nginx -t before reloading. This command checks for syntax errors and ensures that the configuration is valid. Regular testing helps prevent accidental overrides or misconfigurations that could disrupt URL routing.
For more examples of creating structured URL lists from location directives, see
Creating List of URLs from Nginx Location Directive. This resource provides practical templates for organizing complex routing rules.
Frequently Asked Questions
Does Nginx sort location blocks alphabetically?
No, Nginx does not sort location blocks alphabetically. It uses a strict precedence model based on specificity, where exact matches and longer prefixes take priority over shorter ones. Regex blocks are evaluated in the order they appear in the file.
How can I force a specific location block to take precedence?
You can use the
= modifier for exact matches or
^~ for prefix matches to stop further regex processing. For regex blocks, ensure the desired block appears earlier in the configuration file, as the first match wins.
What happens if no location block matches a URL?
If no location block matches, Nginx uses the default server block's root directory and index file. This typically results in serving the default page or triggering a 404 error if no index file exists.
Why are my regex locations not working as expected?
Regex locations are evaluated in the order they appear in the config file. If an earlier regex block matches the URI, subsequent blocks are ignored. Ensure your regex patterns are specific enough and ordered correctly.
Can I use variables to control location selection?
Yes, you can use variables within location blocks to dynamically determine behavior. However, variable expansion occurs during request processing, so it does not change the static precedence rules defined in the configuration file.