When configuring Apache, one of the most confusing aspects is how the server handles multiple <Location>
sections that match the same request URI. The merging behavior isn't always intuitive, especially when directives conflict between sections.
Apache processes matching <Location>
sections in this order:
- All matching sections are collected
- Sections are sorted by match length (shortest path first)
- Directives are applied in this order, with later directives overriding earlier ones
Let's examine the configuration from the question:
<Location / >
ProxyPass http://backend.com/
Order allow,deny
Satisfy any
</Location>
<Location /sub/foo>
Order allow,deny
</Location>
<Location /sub>
Order deny,allow
Require valid-user
Satisfy all
</Location>
For a request to /sub/foobar
, the merging would occur as follows:
# First: / (shortest match)
ProxyPass http://backend.com/
Order allow,deny
Satisfy any
# Then: /sub (longer than / but shorter than /sub/foo)
Order deny,allow
Require valid-user
Satisfy all
# Finally: /sub/foo (longest match, but doesn't actually match /sub/foobar)
# This section is NOT applied to /sub/foobar
- The
/sub/foo
section doesn't match/sub/foobar
- it must be an exact prefix match - Directives are applied in order of match length, not declaration order
- Later-applied directives override earlier ones for the same directive
Developers often make these mistakes:
# WRONG: Assuming declaration order matters
<Location /longer/path>
# This might not override what you expect
</Location>
<Location />
# This gets applied first despite being declared later
</Location>
To avoid confusion:
- Always consider path length when designing your Location hierarchy
- Use
LocationMatch
for regex patterns when needed - Test configurations thoroughly with
apachectl -t
andapachectl -S
With LocationMatch
, the behavior changes:
<LocationMatch "^/sub/foo">
# This WOULD match /sub/foobar
Order allow,deny
</LocationMatch>
Regex matches are evaluated after all prefix matches, following the same longest-match principle.
When Apache processes requests, it evaluates all matching Location
sections in a specific order. The merging follows these key principles:
- Most specific path wins: The section with the longest matching path prefix takes precedence
- Declaration order matters: For equally specific matches, later declarations override earlier ones
- Directive-specific behavior: Some directives merge while others replace
Let's examine the configuration from the question for a request to /sub/foobar
:
ProxyPass http://backend.com/
Order allow,deny
Satisfy any
Order allow,deny
Order deny,allow
Require valid-user
Satisfy all
The effective configuration for /sub/foobar
would be:
ProxyPass http://backend.com/
Order deny,allow
Require valid-user
Satisfy all
The process works like this:
Location /
matches (base configuration)Location /sub
matches (more specific than /)Location /sub/foo
doesn't match our URL
Directive | Merging Behavior |
---|---|
ProxyPass | Last matching directive takes effect |
Order | Completely replaced by most specific match |
Satisfy | Replaced by most specific match |
Require | Accumulates from all matches |
Consider this more complex example:
ProxyPass http://api-v1.example.com/
SetEnv API_VERSION 1
ProxyPass http://api-v2.example.com/
SetEnv API_VERSION 2
Require valid-user
AuthType Basic
For a request to /api/v2/user/profile
, the effective configuration would be:
ProxyPass http://api-v2.example.com/
SetEnv API_VERSION 2
Require valid-user
AuthType Basic
Use these techniques to verify your configuration:
# Check merged configuration
apachectl -S
# Test specific URL processing
apachectl -t -D DUMP_RUN_CFG -D DUMP_URI=/sub/foobar
- Place more specific paths after general ones
- Avoid conflicting directives in overlapping locations
- Use
LocationMatch
for regex patterns - Document merge behavior in complex setups