2

this is Apache httpd 2.4.

I am trying to port a legacy installation from 2.2 to 2.4 and clean it up a bit in the process. There are a lot off directories with identical setup, interspersed with a few dirs that differ. In essence, it looks like this:

<directory /var/www/aaa >
  # lots of stuff
</directory>
<directory /var/www/bbb >
  # lots of stuff
</directory>
<directory /var/www/ >
  # lots of stuff
</directory>
<directory /var/www/ccc >
  # lots of other stuff
</directory>

I'd love to avoid redundant lines, so I'm wishing for some sort of shorthand, like:

<directory /var/www/aaa >
<directory /var/www/bbb >
<directory /var/www/ >
  # lots of stuff
</directory>

<directory /var/www/ccc >
  # lots of other stuff
</directory>

But <Directory> doesn't support multiple dirs in any way that I can find. So <DirectoryMatch> seems appropriate, like this:

<directoryMatch /var/www/(aaa|bbb|) >
  # lots of stuff
</directory>

<directoryMatch /var/www/ccc >
  # lots of other stuff
</directory>

This fails, as the /var/www/(aaa|bbb|) matches /var/www/ccc in partial. And contrary to <Directory>, <DirectoryMatch> is not processed in the order shortest directory component to longest. The manual claims that "within each group the sections are processed in the order they appear in the configuration files", but even if I switch the sections, the result is still the same (that /var/www/ccc is hit by "# lots of stuff" instead of by "# lots of other stuff").

In this example, I can of course extend the regexp (/var/www/(aaa|bbb|(?!ccc))), but the real configuration is unfortunately much more complex than this. Working with the regex is probably still a possibility, but the result will hardly be easy to understand or maintain.

So can someone give me a hint if there is some way to do this, beside the DirectoryMatch? And perhaps an explanation for why Apache seems to prefer the partial match above? Thanks.

2
  • Don't use /var/www/(aaa|bbb|), use ^/var/www/(aaa|bbb|)/
    – wurtel
    May 2 '19 at 14:33
  • Can you give an example of what's inside Directory? Maybe there is a simpler solution, because <Directory /var/www/> also matches everything below this directory like /var/www/aaa...
    – Freddy
    May 2 '19 at 18:42
0

There isn't an easily readable way to use DirectoryMatch to match all of /var/www/aaa, /var/www/bbb, and /var/www, but not /var/www/ccc. This is because /var/www includes all of the other three directories.

What may be easier is to use mod_macro to define common sections of configuration, and then apply them using Directory as in your original example.

a2enmod macro                # Enable the mod_macro module
systemctl restart apache2    # YMMV but this is the systemd way

You can then define your macro. Here's one I use

# Logging
#
<Macro CronoLogger $vHost>
    ServerSignature On
    LogLevel warn
    ErrorLog "|/usr/bin/cronolog /home/www/$vHost/logs/%Y/%m/%d/public-error.log"
    CustomLog "|/usr/bin/cronolog /home/www/$vHost/logs/%Y/%m/%d/public-access.log" combined
</Macro>

and I include it in a vHost definition like this

Use CronoLogger www.contoso.com

In your case, with an example macro StandardStuff param1 param2 you could use it like this

<Directory /var/www>
    Use StandardStuff /var/www /
</Directory>

<Directory /var/www/aaa>
    Use StandardStuff /var/www /aaa
</Directory>

<Directory /var/www/bbb>
    Use StandardStuff /var/www /bbb
</Directory>

<Directory /var/www/ccc>
    # Do non-standard stuff here
    #
</Directory>
1
  • mod_macro seems to be exactly what I was looking for (for this problem and a lot more in fact). I didn't know this one. Thanks!
    – NoMann
    May 3 '19 at 9:01
0

The manual claims that "within each group the sections are processed in the order they appear in the configuration files", but even if I switch the sections, the result is still the same (that /var/www/ccc is hit by "# lots of stuff" instead of by "# lots of other stuff").

They are both processed as both directives match.

Enable mod_headers (a2enmod headers) and try

<DirectoryMatch /var/www/(aaa|bbb|)>
    Header add AAA one
</DirectoryMatch>
<DirectoryMatch /var/www/ccc>
    Header add AAA two
</DirectoryMatch>

and you will see with your developer tool that the response of http://localhost/ccc contains both headers.

If you want to match /var/www, /var/www/foo.html, /var/www/aaa /var/www/aaa/bar, /var/www/bbb, /var/www/bbb/baz, then this should work:

<DirectoryMatch ^/var/www/([^/]*|aaa/.*|bbb/.*)$>
  • [^/]* matches anything inside /var/www/ which is not a directory
  • aaa/.*|bbb/.* matches anything inside including subdirectories
  • $ is important here, otherwise the regex only defines the beginning of the matching directory and more than you want

If you only need to match the directories (and no other files inside), use

<DirectoryMatch ^/var/www(/aaa|/bbb)?/?$>

I would probably prefer a LocationMatch (if possible), so you don't have to care about the directory structure.

3
  • Thanks for repairing my regexp, I'll need that one too, even if i go with mod_macro.
    – NoMann
    May 3 '19 at 9:18
  • To your question which directive matches first: It's the first directive in the headers example. I adjusted the example so you can see it in the response. If you switch the directives, then /var/www/ccc matches first. It really is the order they appear in the config.
    – Freddy
    May 3 '19 at 9:25
  • Thanks for clearing that up. I must have botched something else, when I tried it (maybe forgot to restart httpd).
    – NoMann
    May 3 '19 at 12:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.