1

Sorry if this has been asked/answered before, but I was not able to find an answer to this particular problem.

If I create a .htaccess file with a simple rewrite rule, that rule works. If I create another .htaccess file in a Subdirectory with it's own rewrite configuration, then the main .htaccess file at the top level stops being read. I don't even need to create any rules. Simply turning on the rewrite engine on the subdirectory causes the higher level rewrites to stop working.

I created a set of subdirectories with two Text files:

[root@apachetest html]# cat test/1/test.txt
1

[root@apachetest html]# cat test/2/test.txt
2

And an .htaccess file to rewrite test/1/test.txt to test/2/test.txt

[root@apachetest html]# cat test/.htaccess 
RewriteEngine on
RewriteRule 1/test.txt 2/test.txt [L]

This works as expected. If I request 1/test.txt I get 2/test.txt

[root@apachetest html]# curl localhost/test/1/test.txt
2

But if I create another .htaccess file inside the test/1/ Subdirectory, then the test/.htaccess file stops working.

[root@apachetest html]# echo "RewriteEngine On" > test/1/.htaccess
[root@apachetest html]# curl localhost/test/1/test.txt
1

I have tried all of the RewriteOptions; Inherit, InheritBefore, InheritDown, InheritDownBefore, and IgnoreInherit in both the /test/.htaccess and the /test/1/.htaccess but I am unable to get the /test/.htaccess RewriteRule to work if /test/1/.htaccess has any rewrite configurations in it.

I need to be able to put RewriteRules in the subdirectory without affecting the RewriteRules in the top level directory. Can anyone tell me what I am missing?

1 Answer 1

1

Yes, by default, mod_rewrite directives are not inherited by child configs. So, if you have mod_rewrite directives in a subdirectory .htaccess file (even just enabling or disabling the rewrite engine) then the mod_rewrite directives in the parent directory/config are completely overridden - they are not processed at all.

I have tried all of the RewriteOptions; Inherit, InheritBefore, InheritDown, InheritDownBefore, ...

Yes, this is what you need to do in order to enable mod_rewrite inheritance. Which option you choose is dependent on where and when you want the parent/child directives to be inherited.

HOWEVER, the "problem" is the way in which the mod_rewrite directives are "inherited". They are inherited by effectively copying the directives into the respective config. They are not processed in the context of their original config. This effects things like relative URL-paths. Normally, the RewriteRule directive matches a URL-path that is relative to the directory that contains the .htaccess file. However, if those directives are "inherited" (ie. effectively copied) into a child config then those relative URL-paths are going to be different and the rule may no longer match.

The "inherited" directives need to be written in such a way that they are not dependent on the directory in which they are processed - so you can't necessarily rely on the RewriteRule pattern when inheriting directives in a directory context.

So, using your example...

# test/.htaccess 
RewriteEngine on
RewriteRule 1/test.txt 2/test.txt [L]

And we enable mod_rewrite inheritance in the /test/1 subdirectory .htaccess file:

# test/1/.htaccess 
RewriteEngine on

RewriteOptions Inherit

This effectively results in the following being processed when requesting /test/1/test.txt:

# test/1/.htaccess 
RewriteEngine on

RewriteOptions Inherit

# Due to "Inherit" option the inherited directives from the parent config
# are effectively copied in-place after the existing directives...
RewriteRule 1/test.txt 2/test.txt [L]

Clearly, the RewriteRule pattern 1/test.txt in the test/1/.htaccess file is never going to match so the rule does nothing. (The rule would need to be modified to match just test.txt, but the substitution would also need to modified as well, otherwise it would rewrite the request to /test/1/2/test.txt - which doesn't exist.)

The directives in the inherited/parent config would need to modified to avoid the dependency on the directory in which the parent .htaccess is located. For example:

# test/.htaccess 
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/([^/]+)/1/test\.txt$
RewriteRule (^|/)test\.txt$ /%1/2/test.txt [L]

The condition effectively repeats the test for test.txt, but is more specific. You could make the RewriteRule pattern entirely generic, but the rule will then be processed for every request.

NB: I captured the first path segment and used the corresponding backreference %1 in the substitution to avoid having to hardcode the directory in which the .htaccess file is located.

This "inheritance" modal is more problematic/complex when mod_rewrite is used in a directory (.htaccess) context. (mod_rewrite is generally more complex anyway when used in a directory context.) The relative path issue is not an issue with directives in the server config / virtualhost since the paths are all root-relative.

1
  • 1
    Thank you for your detailed and thoughtful reply. This is perfect. With this information I was able to resolve the real world issue I have been fighting with for weeks!
    – KBM
    Commented Feb 22 at 22:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .