46

I'm working on some basic apache configuration, but I don't understand precisely how apache merges different <Location> sections when several of them match an incoming requests URL. The apache documentation in its "How the sections are merged" chapter is a little bit confusing when it comes to the order/priority of several matching sections of the same type.

For example, imagine the following apache configuration (ignore whether the actual contents make sense or not, I'm only interested in the application order of each rule/section):

<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>

<Location /doesnt/match >
  ProxyPass !
</Location>

Now if a client makes a request to /sub/foobar, which is the final configuration that will be applied to this request?

Is the applied configuration the equivalent of:

# All the directives contained in all the matchin Locations in declaration order
ProxyPass http://backend.com/
Order allow,deny
Satisfy any
Order allow,deny
Order deny,allow
Require valid-user
Satisfy all

or maybe

# same as above, but with longest matching path last
ProxyPass http://backend.com/
Order allow,deny
Satisfy any
Order deny,allow
Require valid-user
Satisfy all
Order allow,deny

or something completely different.

Thanks for your help, I'm really confusing.

LordOfThePigs
  • 697
  • 1
  • 7
  • 7

2 Answers2

59

The order of merging is fairly complicated, and it's easy to be caught out by exceptions... The apache doc is "How the sections are merged"

According to that documentation, the order of merging of sections is done by processing all of the matching entries for each match type in the order that they are encountered in the configuration files, with the last match winning. (with the exception of <Directory>, which is treated in order of path specificity).

The order of types is Directory, DirectoryMatch, Files, and finally Location. Later matches overwrite earlier matches. (*ProxyPass and Alias are treated differently again, see note at end)

And there are several important exceptions to these rules that apply to using ProxyPass, and ProxyPass in a <Location> section. (see below)

So from your example above requesting http://somehost.com/sub/foobar with the follwing config;

<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>

<Location /doesnt/match >
  ProxyPass !
</Location>

It would accumulate the following directives ....

  ProxyPass http://backend.com/
  Order allow,deny
  Satisfy any
  Order allow,deny
  Order deny,allow
  Require valid-user
  Satisfy all   

With the later matches eliminating the previous duplicates, resulting in;

  ProxyPass http://backend.com/
  Order deny,allow
  Require valid-user
  Satisfy all   

Explanation
Later matches overwrite earlier matches with the exception of <Directory> where matches are processed in the order: shortest directory component to longest.

So for example,
<Directory /var/web/dir>
will be processed before
<Directory /var/web/dir/subdir>
regardless of what order those directives were specified in the config, and the more specific match wins.

Any matching Location directive will always override a previously matching Directory directive.

The basic idea is that for a request like GET /some/http/request.html internally it will be translated to a location in the filesystem via an Alias, ScriptAlias or for a normal file location under the DocumentRoot for the VirtualHost that it matched.

So a request will have the following properties which it uses for matching:
Location: /some/http/request.html File: /var/www/html/mysite/some/http/request.html Directory: /var/www/html/mysite/some/http

Apache will then apply in turn all of the Directory matches, in the order of directory specificity, from the config, and then in turn apply DirectoryMatch, Files, and finally Location matches in the order in which they are encountered.

So Location overrides Files, which overrides DirectoryMatch, with paths matching Directory at the lowest priority. Hence in your example above, a request to /sub/foobar would match the first 3 Location in order, hence the last one wins for conflicting directives.

(You are right that it is not clear from the docs how some of the edge cases are resolved, its possible that any allow from * type directives would be connected to the associated Order allow,deny, but I didn't test that. Also what happens if you match Satisfy Any but you have previously collected an Allow from *...)

interesting note about ProxyPass and Alias

Just to be annoying, ProxyPass and Alias appears to work in the other direction.... ;-) It basically hits the first match, then stops and uses that!

Ordering ProxyPass Directives

The configured ProxyPass and ProxyPassMatch rules are 
checked in the order of configuration. 
The first rule that matches wins. So
usually you should sort conflicting ProxyPass rules starting with the
longest URLs first. Otherwise later rules for longer URLS will be
hidden by any earlier rule which uses a leading substring of the URL.
Note that there is some relation with worker sharing.

For the same reasons exclusions must come before the general 
ProxyPass directives.

so basically, Alias and ProxyPass directives have to be specified, most specific first;

Alias "/foo/bar" "/srv/www/uncommon/bar"
Alias "/foo"     "/srv/www/common/foo"

and

ProxyPass "/special-area" "http://special.example.com" smax=5 max=10
ProxyPass "/" "balancer://mycluster/" stickysession=JSESSIONID|jsessionid nofailover=On

However, as @orev has pointed out. You can have a ProxyPass directive in a Location directive, and so a more specific ProxyPass in a Location will beat out any previously found ProxyPass.

Tom
  • 10,886
  • 5
  • 39
  • 62
  • 3
    Thanks for flagging the warning about Ordering ProxyPass Directives. Saved me a great deal of headache – Jeremy French Jun 15 '12 at 13:52
  • 5
    Regarding `ProxyPass` _"working in the other direction"_, this is only true if they're outside of a ``. Inside a ``, the rules of merging `` are followed, meaning you want your least-specific `` directives to come _before_ the more specific ones. This allows the more specific ones to override the less specific directives. You can only have one `ProxyPass` per ``. – orev Sep 14 '18 at 03:30
0

If you nest section (eg. ): Nested sections are merged after non-nested sections of the same type. This means if you add an block to a non-nested configuration your last-matching section changes.

Nobody
  • 1