Excluding a directory from a root .htaccess rewrite rule to allow it to be password protected?

I have spent a tremendous amount of time the last week trying to figure this out, but no matter what I try I cannot get this to work. My web host said they did not have anyone who knew enough about .htaccess files to get this working (encouraging, right?), and the company I purchased my CMS from also could not determine a solution. I've also read dozens upon dozens of answers on here and on other websites, but I simply cannot fix my problem.

Here's the deal: My CMS - Invision Power Board - generates the following .htaccess file which goes in the root of the website:

<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} .*\.(jpeg|jpg|gif|png)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . /public/404.php [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

I have a subdirectory, sub_dir, that I need to password protect using a .htaccess file in the subdirectory. I setup the password protection through cPanel and if the .htaccess file in the root of the website is disabled it works fine. If the .htaccess file in the root of the website is not disabled, however, then when I browse to sub_dir the homepage is displayed. At first I thought the homepage being displayed might have something to do with the 404 page rewrite, but the homepage is still displayed even if I remove the rewrite conditions and rule for the 404 page.

The code in the .htaccess file in sub_dir is:

AuthUserFile "/home/[user]/public_html/.htpasswd"
AuthType Basic
AuthName "subdir"
require valid-user

As I previously mention, the password protection works when the .htaccess file in the root directory is disabled. It also works when I remove the bottom rewrite conditions and rule (the lines for index.php), but removing the rewrite conditions and rules for the 404 page does not affect anything.

I have tried dozens of potential solutions, none of which have worked. To name a few, I tried Poncha's answer below:

RewriteCond %{REQUEST_URI} !^sub_dir

I've also tried this:

RewriteRule ^/sub_dir  - [L]

As well as many, many other things that I don't really even remember now. The point is, nothing has worked so far. I also did try all possible combination with regard to the leading and following slashes.

My server is running Apache 2.2.22.

I am seriously at my wits end here. Please help.

Answers


It would seem like you've already tried this, it's the most obvious answer (as poncha pointed out) and it's probably the most likely to show up in a mod_rewrite tutorial/guide. By exlcuding the directory using a RewriteCond, noting that the match of the condition is against the %{REQUEST_URI}, which begins with a /":

<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/sub_dir
RewriteCond %{REQUEST_FILENAME} .*\.(jpeg|jpg|gif|png)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . /public/404.php [L]

RewriteCond %{REQUEST_URI} !^/sub_dir
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

EDIT:

Looking at what you've tried, this also is wrong. You don't want the leading slash in the match of the RewriteRule when it is in an htaccess file:

<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On

RewriteRule ^sub_dir  - [L]


RewriteBase /
RewriteCond %{REQUEST_FILENAME} .*\.(jpeg|jpg|gif|png)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . /public/404.php [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

This rule forwards to the homepage if the requested path is not an existing file, and is not an existing directory.

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

Clearly, because you are being forwarded to the homepage, the server believes that either the sub_dir directory does not exist, or the request for sub_dir is being redirected to something which does not exist.

The first thing to check in this scenario is, of course, whether sub_dir is an actual directory, keeping in mind that depending on your the directory name will be case sensitive in most cases where Apache is being run, and also keeping in mind that a symlink is not necessarily treated the same as a directory.


How about you try just doing this in your sub_dir .htaccess to disallow modrewrite to propagate into your sub_dir :

    ## turn off rewrite engine
    RewriteEngine Off
    ## now do your auth stuff
    AuthUserFile "/home/[user]/public_html/.htpasswd"
    AuthType Basic
    AuthName "subdir"
    require valid-user

and if you really need rewrite rules to work inside sub_dir then do them specifically in that .htaccess file so there is never any confusion. As soon as you execute RewriteEngine On/Off then the rules from the parent folder do not apply directly. They are read from that folder first then the root.


First notice:

AuthUserFile "/home/[user]/public_html/.htpasswd"

It looks like your .htpasswd file is in a publicly accessible place (public_html). This is a security problem, you shoul dput that file somewhere where the apache user can read it (check directory anf files rights) but certainly not on a place under a DocumentRoot. No one shoul dbe able to requets directly for a .htpasswd file, it's a server-side only file. But that's not related to your problem.

Your main problem is that you did not answer @Jon Lin & @mootinator questions. What files are you trying to request in sub_dir, is there some html files there, another index.php file? Should you allow directory listing in this directory? How do you make your tests.

When a request on sub_dir is made the parent .htaccess is applied by default (trying to redirect every request you can imagine to a boostrapper index.php, except for missing images files and except for existing directories or files). So by requesting a real file in sub_dir you should'nt have any problem with theses rules. A good way to test that is to comment Rules on your root .htaccess.

You said you made some tests without the root .htaccess file and it worked. So it's maybe the removal of Options -MultiViews which made your tests ok. MultiViews is part of content-negociation and is a very magical word with some very strange behaviors, so let's say for example you are requesting subd_dir/foo in your tests MultiViews could find a file sub_dir/FoO.html and serve it. Remove MultiViews and your tests will not work anymore (maybe). @Mootinator proposals on symbolic links problems could also be valid, and you could also have something in the tested files redirecting to an url catched by the first rule, there is no end to strange things. But for sure "it does not work" is not enough, what is "it"?

As I said you need to give us more information. And give all other readers (even in the future) enough element to see if your problem could be related to their problems. The goal is not to hire some experts to work directly on your server but to get valid answers to valid and detailled problems.


The solutions above don't work because they don't address the fundamental problem which is that the sub-folder to be excluded from the rules is password protected.

When the initial access is rejected by Apache and the login dialog box is presented, the rewrite rules kick in but can't redirect the client to an accessible file, so the 404 error occurs. To solve this problem we need to provide a "dummy" file to which the client can be directed when the initial access attempt fails.

ErrorDocument 401 /failed_auth.html
RewriteCond %{REQUEST_URI} ^/pwd-protected-sub-folder/(.*)$ [OR]
RewriteCond %{REQUEST_URI} ^/failed_auth.html$
RewriteRule ^.*$ - [L]

Add another RewriteCond to exclude your desired sub_dir (to both rules):

RewriteCond %{REQUEST_URI} !^sub_dir

Adding this in the hope that it helps someone else. @Mike L was on the right track with this I think. I had a similar situation (htaccess password protected sub-directory with rewrite rules in the root htaccess which I still needed for the main site). The solution for me in the end was to simply add this to the root .htaccess file.

ErrorDocument 401 "Unauthorised"

You'll still need to add the relevant rules to allow access to the sub-directory of course, but the password request not displaying was fixed using the above. Hope it helps!


For a site using plain vanilla cPanel-based shared hosting (Apache 2.2), I solved what appears to be the same problem by adding a file named "401.shtml" to the document root (public_html). The mere existence of the file, without even an ErrorDocument 401 directive in the .htaccess, solved the problem.


Need Your Help

File/Data transfer between two node.js servers

javascript node.js socket.io

I am trying to set up a small system having one server (aka sensor) transfer data files to another server (aka server) (both running node.js apps) when it sees that the other is available.

Session conditions in a symfony2 controller

php symfony redirect layout controller

When working with symfony2, I'd like to show different layouts (base.html.twig for guests, and layout.html.twig for logged users).