I have several document root directories, /opt/lampp/htdocs/proj1
, /opt/lampp/proj2
, etc, that have AuthType Basic
password protection. I want their uploads
sub-directory trees not to require a password. Except that the private
sub-directory tree of uploads
should not allow any access at all. According to http://httpd.apache.org/docs/current/mod/core.html#directory :
Regular expressions are not considered until after all of the normal sections have been applied. Then all of the regular expressions are tested in the order they appeared in the configuration file.
So I used these directives:
#==========================================================
# regexp enables access to images without login (needed for wp_sideload_image)
<Directory ~ "/opt/lampp/htdocs/[^/]*/public/(uploads|wp/wp-content/uploads)">
Require all granted
</Directory>
#==========================================================
# regexp protects private uploads unconditionally
# regexps processed in source order, so MUST BE AFTER ENABLING IMAGES
<Directory ~ "/opt/lampp/htdocs/[^/]*/public/uploads/private">
Require all denied
</Directory>
What I found was that the Require all denied
directive was not effective, everything below uploads could be accessed without a password, including things below private. Just for fun I tried removing the alternation expression, making the first block:
<Directory ~ "/opt/lampp/htdocs/[^/]*/public/uploads">
Require all granted
</Directory>
And much to my surprise (and delight), things worked as I wanted. So I can get the effect of the original regular expression by adding another <Directory>
:
<Directory ~ "/opt/lampp/htdocs/[^/]*/public/wp/wp-content/uploads">
Require all granted
</Directory>
While that does work, I might as well use normal <Directory>
blocks with a '*
' wildcard for the level below htdocs
. I thought it would be more concise to use the regexp form. I still want to use regexp for the private section, though, since I need that to be processed after the directives that grant access.
Can anyone explain why the original code doesn't work? The Apache docs say they use PCRE, and the expression using alternation works fine with egrep
. Plus I don't see how that expression could affect the subsequent Require all denied
, since they are both regexps, which are supposed to be processed in source order. So the denied directive should override no matter what, shouldn't it? That's what happens when I replace the alternation with two separate regexp directives. What am I missing?
EDIT: At the time I posted this, I was obviously having a brain fart moment thinking that the non-regexp rule of
"shortest path first"
meant that I needed to use a regexp to ensure that the"Require all denied"
would be processed late enough. But clearly, while there could be longer paths below"uploads"
than those below"uploads/private"
, in those cases there wouldn't be a match on"uploads/private"
, so those paths shouldn't be forbidden anyway. Thus I believe the "best" solution for my actual situation is simply to eliminate the use of"regexp"
matching entirely and use three normal"<Directory>"
directives with wildcards similar to the ones shown with regexps above, but replacing the"[^/]*"
regexp with the shell wildcard"*"
. That works just fine, and likely is microseconds faster :-)However, I'd still like to know why my original code did not work. It still seems to me that Apache's treatment of the directive containing the
"|"
regexp operator was incorrect.