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

22,207

Solution 1

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>

Solution 2

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]

Solution 3

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.

Solution 4

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.

Solution 5

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.

Share:
22,207

Related videos on Youtube

Nate
Author by

Nate

I'm a senior in college, majoring in EE and minoring in CS, with a passion for electronics and programming. I'm an entrepreneur and started a small hobby electronics company called FoxyTronics a few years ago, and am now working on launching a shopping website called PriceWombat.

Updated on September 18, 2022

Comments

  • Nate
    Nate over 1 year

    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.

    • Jon Lin
      Jon Lin almost 12 years
    • Admin
      Admin almost 12 years
      @JonLin - Oops, my bad. I thought I had deleted that question. I asked that this morning and, in addition to no one responding, the question became convoluted as I made updates to it as I tried different things. This question is clear and concise. I deleted my old question. Thanks.
    • mootinator
      mootinator almost 12 years
      It isn't clear to me what exactly the behavior you're expecting is. Is there an index.html or index.php in the target folder you want it to load, or are you expecting a password protected directory listing? If you try to directly access an actual file in the subfolder, does it work as expected? (It should).
    • Admin
      Admin almost 12 years
      Hmmm.. I guess what I'm not seeing is what urls you accessed to verify the settings. Knowing those might make it easier to diagnose, as you might not be testing for a condition that would shed some light on this. Also, you posted the .htaccess for the root of the website... but what is in the httpd.conf file?
  • Admin
    Admin almost 12 years
    Thanks for your help. I tried that, and I'm afraid it did not work. Any other ideas?
  • Admin
    Admin almost 12 years
    Jon - Thank you for your answer, but I'm afraid it did not work :(.
  • Jon Lin
    Jon Lin almost 12 years
    @Nate Without any detailed explanation of how it isn't working, we're not going to be able to help you any further.
  • Admin
    Admin almost 12 years
    I'm afraid that did not work either. If I gave you ftp access, could you give it a try?
  • Anthony Hatzopoulos
    Anthony Hatzopoulos almost 12 years
    If it is a symlink you can test with !-l (is not symbolic link). httpd.apache.org/docs/2.0/mod/mod_rewrite.html#rewritecond