When attempting to nest prefix-based location blocks inside a regex location block with alternation (the | operator), Nginx throws a specific error because of how location matching works internally. The error message "location \"/a\" is outside location \"/a|/b\""
reveals a fundamental constraint in Nginx's configuration parsing.
Nginx processes location blocks in a specific order:
1. Exact match locations (=) first
2. Prefix-based locations (/) next
3. Regex locations (~) last
The key problem is that nested locations must be strictly contained within their parent location's match pattern. When using ~ /a|/b
, the regex doesn't create a proper containment relationship for the individual prefix locations.
Here are three production-tested approaches:
Option 1: Using Include Directives
location /a {
include shared-config.conf;
# a-specific directives
}
location /b {
include shared-config.conf;
# b-specific directives
}
Option 2: Map-Based Routing
map $uri $route {
~^/a 'a';
~^/b 'b';
}
server {
location / {
# Shared config
proxy_set_header X-Custom-Header "value";
# Route-specific configs
if ($route = 'a') {
# a-specific config
}
if ($route = 'b') {
# b-specific config
}
}
}
Option 3: Prefix Capture Groups
location ~ ^/(a|b) {
# Shared config
set $prefix $1;
location ~ ^/a/ {
# a-specific config
}
location ~ ^/b/ {
# b-specific config
}
}
Each approach has different performance characteristics:
- Include files are parsed at configuration load
- Map variables add minimal runtime overhead
- Nested regex locations have matching overhead
For high-traffic sites, benchmark with nginx -T
and stub_status
to measure impact.
Here's how we implemented shared CORS headers across multiple endpoints:
# cors-shared.conf
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
# main config
location /api/v1/users {
include cors-shared.conf;
proxy_pass http://user_service;
}
location /api/v1/products {
include cors-shared.conf;
proxy_pass http://product_service;
}
When troubleshooting location blocks:
- Use
nginx -T
to test configuration - Enable debug logging with
error_log /var/log/nginx/error.log debug;
- Check evaluation order with
curl -v
requests
When working with Nginx configuration, you might encounter a puzzling error when trying to nest location blocks with regex patterns:
nginx: [emerg] location "/a" is outside location "/a|/b" in /etc/nginx/nginx.conf:36
This occurs specifically when attempting to use regex alternation (|
) in the parent location block while trying to nest exact match locations.
Nginx processes location blocks in a specific order and has limitations when combining different matching types:
- Regex locations (
~
) and prefix locations have different matching behaviors - Nginx doesn't support nesting exact match locations inside regex locations with alternation
- The error suggests Nginx can't properly scope the nested locations within the regex pattern
Here are several approaches to achieve your goal without repetition:
Option 1: Using Common Configuration with Includes
# Define common configuration in a separate file
# common.conf
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
# ... other common directives
# Main configuration
location /a {
include common.conf;
# specific directives for /a
}
location /b {
include common.conf;
# specific directives for /b
}
Option 2: Using Regex Capture Groups
location ~ ^/(a|b) {
# Common directives
proxy_pass http://backend;
# Specific handling based on capture
if ($1 = "a") {
# /a specific configuration
}
if ($1 = "b") {
# /b specific configuration
}
}
Option 3: Map Directive for Complex Routing
map $uri $backend {
~^/a backend_a;
~^/b backend_b;
}
server {
location / {
proxy_pass http://$backend;
# Common configuration here
}
}
When structuring Nginx configurations:
- Prefer prefix matches (
location /path/
) over regex when possible - Use
include
directives to avoid configuration duplication - Consider using
map
for complex routing logic - Test configuration changes with
nginx -t
before reloading
Remember that:
- Regex locations are evaluated sequentially until a match is found
- Exact match locations (
=
) and prefix locations have higher priority - Nested locations can impact performance if overused