Search code examples
apache.htaccesshttp-redirectmod-rewritesubdomain

.htaccess redirecting URL but not content for subdomain


I'm trying to set up a test site but having real trouble getting .htaccess to redirect properly.

I want the contents of www.example.com/test to show when a user types in test.example.com. My rewrite rules allow me to use test.example.com in the address bar, but it's actually showing me the content of the root (www.example.com), not the test subfolder.

I'm not an .htaccess guru by any stretch, but I've been using Stack Overflow for 5 years and this is the first time I've been stumped enough to ask a question! Your collective wisdom is appreciated.

Here's the relevant part of my .htaccess code:

RewriteEngine On

# Rewrite for http cases
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L]

# Rewrite for no www cases
RewriteCond %{HTTP_HOST} !www\.example\.com [NC]

#redirect for test subdomain
RewriteCond %{HTTP_HOST} !^test\.example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]

# redirect to correct for old subfolder usage
RewriteRule ^oldsubfolder/$ https://www.example.com/ [L,R=301]

Solution

  • I want the contents of www.example.com/test to show when a user types in test.site.com.

    I assume you just have one domain and test.site.com should really be test.example.com (which would seem to be consistent with the rest of your question)?

    In the code you've posted, there's nothing that really attempts to do this redirect? In the code you've posted, a request for test.example.com would not be redirected - so if it is then you may be seeing a cached response. Clear your browser cache.

    You would need something like:

    RewriteCond %{HTTP_HOST} ^(?:www\.)?(test)\.example\.com [NC]
    RewriteRule (.*) http://www.example.com/%1/$1 [R,L]
    

    The (?:www\.)? part simply catches an optional www subdomain of the subdomain! Depending on how this subdomain was created, both test.example.com and www.test.example.com might be accessible. (Although I suspect your SSL cert probably doesn't allow this anyway?)

    %1 is a backreference to the captured group in the CondPattern (ie. test) and $1 is a backreference to the captured RewriteRule pattern. Capturing the subdomain (eg. "test") just avoids repetition, but also allows for more than one subdomain to be handled by the same rule.

    This is also a temporary (302) redirect. Change this to a 301 only when you are sure it's working (if that is the intention). 301s are cached by default, so can make testing problematic.

    Clear your browser cache before testing.


    # Rewrite for no www cases
    RewriteCond %{HTTP_HOST} !www\.example\.com [NC]
    
    #redirect for test subdomain
    RewriteCond %{HTTP_HOST} !^test\.example\.com$ [NC]
    RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
    

    The comment in the middle of this block would seem to be misleading (it doesn't "redirect for test subdomain"). The whole block just redirects to www, excluding the test subdomain. The other code then redirects the subdomain.


    UPDATE:

    I was hoping it would continue to show test.example.com in the address bar

    Yes, this is possible. Providing test.example.com and www.example.com point to the same filesystem then you can simply rewrite the request without actually changing the host. For this example, I'll assume test.example.com and www.example.com point to the same document root.

    Change the above redirect to the following rewrite:

    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteCond %{HTTP_HOST} ^(?:www\.)?(test)\.example\.com [NC]
    RewriteRule (.*) /%1/$1 [L]
    

    The request now stays on test.example.com and will serve content from test.example.com/test (although this is hidden from the user) since test.example.com and www.example.com are really the same thing.

    The check against REDIRECT_STATUS ensures we are only processing the intial request and not the rewritten request, thus avoiding a rewrite loop. REDIRECT_STATUS is empty on the initial request and set to 200 after the first successful rewrite.

    However, if test.example.com points somewhere entirely different then you'll need to implement a reverse proxy and "proxy" the request to www.example.com in order to "hide" this from the user.