Reputation: 17831
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
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
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
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