Apache Mod-Rewrite – Catch-All Rule Without Duplicate URLs

apache-2.2apache-2.4mod-rewrite

You can make a catch-all rewrite rule for apache that acts somewhat like an alias, but can be implemented in a .htaccess file while an alias can't.

As an example, assuming your document root is a hierarchy like this:

/.htaccess
/test/
/test/.htaccess
/test/file

You can "Alias" all requests to the test folder by making the root .htaccess contain:

RewriteEngine On
RewriteRule ^(.*)$ /test/$1 [L]

And the second .htaccess contain:

RewriteEngine On

This works great, and usually is all you need. It just has one problem – it creates multiple valid urls. Now you can access the file with both /file and /test/file.

Ordinarily this isn't a problem, but if you add a file called /test/test you'll see the problem, as the fake alias stops working entirely. If the subfolder has a complex .htaccess of its own it can cause major headaches.

Is there any way to fake an alias from a .htaccess without the original urls still working? (Any RewriteCond for the subfolder that would check if we've already been rewritten or not?)

Best Answer

... but if you add a file called /test/test you'll see the problem, as the fake alias stops working entirely.

Yes, the second .htaccess file in the subdirectory prevents the URL being rewritten (since mod-rewrite is not inherited by default). You could get around this by just having the one .htaccess file in the document root that rewrites all requests that have not already been rewritten. For example:

RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.*) /test/$1 [L]

The REDIRECT_STATUS environment variable is empty on the initial request and set to 200 (OK) after the first successful rewrite.

However, if you still need a .htaccess file in the subdirectory (for other mod_rewrite directives) then you'll either need to:

  • repeat these directives in the subdirectories .htaccess file. (You then wouldn't strictly need the above RewriteCond directive in the parent .htaccess file.)

  • Or, enable mod_rewrite inheritance. But I think you'd struggle on Apache 2.2. You would probably need something like RewriteOptions InheritBefore (in the subdirectories .htaccess file), which is only available on Apache 2.4.

It just has one problem - it creates multiple valid urls.

The above method resolves this issue as well, since all requests are now rewritten (which is more like how an Apache Alias would behave in the server config).


Otherwise, you would need to ensure that the base subdirectory was unique in order to be able to implement a canonical redirect back to the document root if the base subdirectory was accessed directly. For example:

RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /unique-subdir
RewriteRule (.*) /$1 [R=301,L]

THE_REQUEST holds the first line of the initial request header and does not change when the request is rewritten.

Related Topic