In a directory / .htaccess
context, the code you've posted above won't actually do anything!? So, you are either seeing the result of a cached response, which is quite possible since you are dealing with 301 (permanent) redirects, which are naturally cached by the browser. Or, you have some other code that is performing this redirect?
Also, I can't see where the double slash would be coming from, even if "something" did happen - which further suggests to me that you are seeing a cached response, or something else is going?
(If, however, these directives were directly in the server config, as opposed to .htaccess
(as stated), then these directives probably would do something and you would indeed get a double slash!)
Specifically...
RewriteCond %{DOCUMENT_ROOT}/%1%{REQUEST_FILENAME} -f [OR]
RewriteCond %{DOCUMENT_ROOT}/%1%{REQUEST_FILENAME} -d
In a directory / .htaccess
context, these conditions will never be successful, so the following RewriteRule
directive that performs the redirect will never occur. You probably meant to use the REQUEST_URI
server variable instead of REQUEST_FILENAME
. (However, in a server context, REQUEST_FILENAME
is the same as REQUEST_URI
at the time the request is initially processed.)
REQUEST_FILENAME
already contains the absolute filesystem path that the URI maps to, so prefixing this with the filesystem path of the DOCUMENT_ROOT
and subdirectory is obviously not going to work.
However, I'd question whether you'd really want to do this anyway. (ie. checking for the existence of the requested file/directory in the respective subdirectory before redirecting.) This would seem unnecessary in my opinion and limits the type of "sites" you can host. I think it would be preferable to unconditionally rewrite all requests for the subdomain to the respective subdirectory (if it exists) and allow each "site" to handle the 404 - which allows you to have a custom 404 for each site if you wish.
Also, I think this should be an internal rewrite (to the subdirectory), rather than an external redirect. ie. A request for test.example.com/login
should remain at test.example.com/login
(as far as what the user sees) and not externally redirected to test.example.com/test/login
? Otherwise, what's the point of the subdomain? This would also resolve the issue of form data not being passed through the redirect (because a 301 turns the POST request into a GET).
So, try something like the following instead:
RewriteEngine On
# Don't process requests for the www subdomain or apex domain
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com [NC]
RewriteRule ^ - [L]
# Rewrite all direct requests for subdomains that exist as subdirectories
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com [NC]
RewriteCond %{DOCUMENT_ROOT}/%1 -d
RewriteRule (.*) /%1/$1 [L]
Your previous rules included a condition (repeated for each rule) that excluded requests for the www
subdomain. I've separated this into its own rule.
Previously, you had a pre-check that tested that the subdomain existed as a subdirectory. This is unnecessary if you check the existence of this subdirectory in the second rule block.
The RewriteCond
directive that checks against the REDIRECT_STATUS
environment variable ensures that all direct requests (from the client) get redirected and not internal rewrites - which avoids a rewrite loop. Note that this rewrites all requests (unless there is another .htaccess
file in the subdirectory that uses mod_rewrite), regardless of whether the subdirectory is already prefixed on the URL - this permits the nesting of subdirectories with the same name, to any depth, eg. /test/test/test/<whatever>
. However, it would be preferable for the site subdirectory to be unique in that site.
The absence of the R
flag on the RewriteRule
makes this an internal rewrite instead of an external redirect (so the URL is not updated in the address bar).
And make sure the browser cache is clear!