F.P
F.P

Reputation: 17831

Subdomains with htaccess not working as expected

I know this is a very highly discussed topic, but I can't figure out what I'm doing wrong using my search skills.

With the following folder structure as root of both domain.local and board.domain.local

/
 app/
 bin/
 board/
     index.php
 src/
 vendor/
 web/
     index.php

And this .htaccess in the / folder

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTP_HOST} ^board.domain.local$
    RewriteRule ^(.*)$ board/$1 [QSA,L]
    RewriteCond %{HTTP_HOST} ^domain.local$
    RewriteRule ^(.*)$ web/$1 [QSA,L]
</IfModule>

I get an internal server error when accessing board.domain.local. Accessing domain.local works perfectly and redirects the queries to web/.

Why does the first rewrite not work?

Upvotes: 0

Views: 4221

Answers (3)

TerryE
TerryE

Reputation: 10888

This is really a supplement to Kaz's comment since I agree with them, but it doesn't fit into the comment character limit. If an .htaccess file is processed (in a Per Directory context) if one or more rewrites have occurred which change the URI then an internal redirect occurs. The .htaccess scan is restarted and the rules are evaluated.

By default only one set of rewrite rules is used: and that is those in the lowest .htaccess on the path with RewriteEngine On. So in the case of a domain.local request on the second pass and if DOCROOT/web/.htaccess then this would be executed instead of DOCROOT/.htaccess for requests to domain.local.

Another aspect is the looping problem which I see that you've addressed the second rewritecond on each rule. However, this can fail is you have options such as MultiViews enabled (another bizarre Apache botch which pays havoc with rewrite rules) because this splits the query apart and does subqueries which can foil this type of anti-recursion condition.

So I always turn of MultiViews and DirectoryIndex with search list.

You can also add the [NS] flag to all rules as none are applicable in a subquery. I also set an environment variable END=true to force exit, when I want to do this and use this stopper at the top of my rules:

 RewriteCond  %{IS_SUBREQ}%{ENV:END} true
 RewriteRule  ^                      -    [L]

Upvotes: 0

Kaz
Kaz

Reputation: 58578

You're doing relative path rewrites in a per-directory context without RewriteBase. Why one works but the other doesn't is due to some compensating factor elsewhere which is inconsistent between board and web. The internal server error is likely a loop. Check your error log.

RewriteEngine On
RewriteBase /   # need this sucker
RewriteCond %{HTTP_HOST} ^board.domain.local$
RewriteRule ^(.*)$ board/$1 [QSA,L]
RewriteCond %{HTTP_HOST} ^domain.local$
RewriteRule ^(.*)$ web/$1 [QSA,L]

In a per-directory context, rewrites are done on file system paths, not URL's. The rewrites are done on just the part of the path after the directory, which is stripped off. If you do a relative rewrite, the directory part is put back after. And then, a moronic thing happens: the rewrite is treated as a URL! RewriteBase specifies the prefix to put on the rewrite (instead of naively restoring the path prefix) to make it a valid URL. RewriteBase says, "although we are handling the directory /var/www/docroot it actually represents the URL space / so when URLs are re-generated from rewrites, they should be in that space, and not in /var/www/docroot which is not a URL".

Ask yourself: what is the DocRoot? And so what will the URL-s be coming out of the relative rewrite when the DocRoot is (wrongly) stuck on as a prefix due to the missing RewriteBase? Trace the handling of those bogus URL-s through your configuration and you will surely discover the reason why one gets into an infinite loop and the other doesn't.

Upvotes: 3

Jon Lin
Jon Lin

Reputation: 143886

Try adding a few more conditions to keep the rewrite engine from looping (your URI will eventually become /board/board/board/board/board/board/board/board/ etc.)

RewriteEngine On

RewriteCond %{HTTP_HOST} ^board.domain.local$
RewriteCond %{REQUEST_URI} !^/board
RewriteRule ^(.*)$ board/$1 [QSA,L]

RewriteCond %{HTTP_HOST} ^domain.local$
RewriteCond %{REQUEST_URI} !^/web
RewriteRule ^(.*)$ web/$1 [QSA,L]

Upvotes: 0

Related Questions