htaccess request rewritten to hidden subdir exposes subdir when trailing slash omitted

31 views Asked by At

There's a domain example.com which is an alias for the main domain. My goal is to point example.com to the subdirectory example.com/ of the main site.

This subdirectory has a child directory test/.

.htaccess is

RewriteCond %{HTTP_HOST} ^(www\.)?example\.com$ [NC]
RewriteRule ^(.*)?$ example.com/$1 [L,NC]
  1. https://example.com/test/ -> this works well, it shows ./example.com/test/index.html without any redirects showing the URL as is.

  2. https://example.com/test (no slash at the end) -> works as redirect to https://example.com/example.com/test/, but it changes the URL and adds the unnecessary dir path, WHY?

How to make it work as in #1 in both cases?

1

There are 1 answers

0
MrWhite On

The "problem" is that mod_dir appends the trailing slash to the filesystem directory (with a 301 redirect) after the internal rewrite has occurred (it's only then that Apache knows that it maps to a directory). This is necessary in order to be able to serve the DirectoryIndex (ie. index.html) from that directory (which is also handled by mod_dir).

To resolve this you need to manually append the trailing slash (if the request does ultimately map to a directory) before your internal rewrite in order to canonicalise the URL. Needless to say, the URL that includes the trailing slash is canonical and this is the URL you should be linking to internally.

For example:

# Append trailing slash if the file-path that the URL maps to is a directory
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com [NC]
RewriteCond %{DOCUMENT_ROOT}/example.com/$1 -d
RewriteRule (.+[^/])$ /example.com/$1/ [R=301,L]

# Rewrite Requests to subdirectory
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com [NC]
RewriteRule (.*) example.com/$1 [L]

NB: The regex ^(.*)?$ is the same as simply (.*) and the NC flag was not required on that rule, since the regex is case-insensitive by its very nature.

Aside: The fact that your existing rewrite rule worked at all (and didn't result in a rewrite loop) is dependent on another .htaccess file existing in the /example.com subdirectory that also contains mod_rewrite directives. I have also used this assumption in the rule above. Otherwise, you would need additional checks to avoid a rewrite loop (and unnecessary filesystem checks).

Test first with a 302 (temporary) redirect to avoid potential caching issues. You will need to make sure all (browser) caches are cleared, since the earlier (erroneous) 301 redirect will have been cached by the browser.


Aside:

There's a domain example.com which is an alias for the main domain.

Assuming you are on a shared hosting platform and depending on the type of hosting you have, you can often set the secondary domain as an "Add-on" domain (as opposed to an "Alias"), which effectively allows you to point the secondary domain directly at the subdirectory (with its own DocumentRoot) - so no need for manual URL rewriting in .htaccess.