2

I have a wildcard DNS setup on my server, something like .example.com. In my root folder there are some sites, so what I need is to have something like this: test.example.com should use test directory (I have nearly 50 sites, not only one).

I want to do it with .htaccess file. Currently, I have the following rules in my .htaccess file:

    RewriteEngine On

    RewriteCond %{HTTP_HOST} !^www\. [NC]
    RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$ [NC]
    RewriteCond %{DOCUMENT_ROOT}/%1 !-d
    RewriteRule ^ - [L,R=404]

    RewriteCond %{HTTP_HOST} !^www\. [NC]
    RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$ [NC]
    RewriteCond %{DOCUMENT_ROOT}/%1 -d
    RewriteCond %{DOCUMENT_ROOT}/%1%{REQUEST_FILENAME} -f [OR]
    RewriteCond %{DOCUMENT_ROOT}/%1%{REQUEST_FILENAME} -d
    RewriteRule ^(.*)$ /%1/$1 [R=301,L]

It is doing something i.e. when I hit test.example.com it hits test directory and fetches data but it writes the URL as test.example.com/test// (2 slashes at the end).

Also, when I click on any link (eg. /login) it takes me to test.example.com/login but it is not working while test.example.com/test//login load page but it doesn't send form data that was submitted for login (lost because of 301 redirection).

1 Answer 1

1

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!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.