Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apache mod_rewrite a subdomain to a subfolder (via internal redirect)

I'm trying to write a set of mod_rewrite rules that allow my users to utilize a single folder for doing development on different projects, and not have to mess with adding vhosts for every single project.

My idea to accomplish this, is to set up a "Global VHost" for every single user who needs this ability (only 3-4), the vhost would be something like: .my-domain.com. From there, I want to promote my users to write code as if it were on a domain, and not in a sub folder. For example, if bob was working on a project named 'gnome,' I'd like the URL bob (and anyone else on our internal network) loads to get to this project to be: http://gnome.bob.my-domain.com. But, what I'd like Apache to do, is recognize that "gnome" is a "project" and thus map the request, internally, to bob.my-domain.com/gnome/.

I've got what I thought would work, and it's quite simple, but..it doesn't work! The request just goes into an infinite loop and keeps prefixing the sub domain onto the re-written request URI.

The mod rewrite code i have is:

RewriteEngine On

RewriteCond %{HTTP_HOST}    ^([^.]+)\.bob\.my-domain\.com
RewriteCond %{REQUEST_URI}  !^/%1.*
RewriteRule ^(.*)$      /%1/$1 [L]

I've googled around a bit about this, but I've yet to find any real solutions that work. Has anyone tried this - or maybe, does anyone have a better idea? One that doesn't involve making a virtual host for every project (I've got designers..I think everyone would agree that a designer shouldn't be making virtual hosts..)

Thanks!

Here is a snippet from the rewrite_log:

[rid#838dc88/initial] (3) [perdir /home/bob/http/] strip per-dir prefix: /home/bob/http/index.html -> index.html
[rid#838dc88/initial] (3) [perdir /home/bob/http/] applying pattern '^(.*)$' to uri 'index.html'
[rid#838dc88/initial] (4) [perdir /home/bob/http/] RewriteCond: input='gnome.bob.my-domain.com' pattern='^([^.]+)\.bob\.my-domain\.com' => matched
[rid#838dc88/initial] (4) [perdir /home/bob/http/] RewriteCond: input='/index.html' pattern='!^/%1.*' => matched
[rid#838dc88/initial] (2) [perdir /home/bob/http/] rewrite 'index.html' -> '/gnome/index.html'
[rid#838dc88/initial] (1) [perdir /home/bob/http/] internal redirect with /gnome/index.html [INTERNAL REDIRECT]
[rid#8392f30/initial/redir#1] (3) [perdir /home/bob/http/] strip per-dir prefix: /home/bob/http/gnome/index.html -> gnome/index.html
[rid#8392f30/initial/redir#1] (3) [perdir /home/bob/http/] applying pattern '^(.*)$' to uri 'gnome/index.html'
[rid#8392f30/initial/redir#1] (4) [perdir /home/bob/http/] RewriteCond: input='gnome.bob.my-domain.com' pattern='^([^\.]+)\.bob\.my-domain\.com' => matched
[rid#8392f30/initial/redir#1] (4) [perdir /home/bob/http/] RewriteCond: input='/gnome/index.html' pattern='!^/%1.*' => matched
[rid#8392f30/initial/redir#1] (2) [perdir /home/bob/http/] rewrite 'gnome/index.html' -> '/gnome/gnome/index.html'
[rid#8392f30/initial/redir#1] (1) [perdir /home/bob/http/] internal redirect with /gnome/gnome/index.html [INTERNAL REDIRECT]
[rid#8397970/initial/redir#2] (3) [perdir /home/bob/http/] add path info postfix: /home/bob/http/gnome/gnome -> /home/bob/http/gnome/gnome/index.html

This is just a snippet, there are a few 10s or 100 or so lines of apache basically rewriting /gnome/index.html to /gnome/gnome/gnome/gnome/gnome/index.html, etc before apache hits its rewrite limit, gives up, and throws error 500

like image 691
Jim Rubenstein Avatar asked Jul 22 '09 17:07

Jim Rubenstein


1 Answers

After a few years of ignoring this problem and coming back to it at various points, I finally found a workable solution.

RewriteEngine on
RewriteCond %{HTTP_HOST} ^([^.]+)\.bob\.my-domain\.com
RewriteCond %1::%{REQUEST_URI} !^(.*?)::/\1/
RewriteRule ^(.*)$  /%1/$1 [L]

What I found was that back-references for previous RewriteCond directions are not available in the ConditionPattern parameter of future RewriteConditions. If you want to use a back-reference from a previous RewriteCond directive, you can only use it in the TestString parameter.

The above directives prepend the sub-domain matched in the 1st RewriteCond directive to the RequestURI, delimited by ::. What we then do in the RewriteCond Test String (regex) is re-capture the sub-domain name, then check to make sure our actual RequestURI doesn't begin with that sub-domain as a folder using a back reference within the same regex.

This sounds a lot more confusing than it really is, and I can't take the credit for discovering the answer. I found the answer as a response to another question here, %N backreference inside RewriteCond. Thanks to Jon Lin for answering that question, and unknown to him, my question too!

like image 99
Jim Rubenstein Avatar answered Nov 01 '22 14:11

Jim Rubenstein