6

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

Jim Rubenstein
  • 6,836
  • 4
  • 36
  • 54
  • Added some more information from the rewrite logs, hopefully someone has tried this before, or has some input on how I can get this done! Thanks guys (and gals) – Jim Rubenstein Jul 22 '09 at 18:32

4 Answers4

5

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!

Community
  • 1
  • 1
Jim Rubenstein
  • 6,836
  • 4
  • 36
  • 54
  • Just a note that I had to remove the trailing / on the second RewriteCond to get it to work properly for me. I was able to load my URL with it (a gallery3 installation), but the CSS resources weren't loading properly. Taking off the trailing slash fixed it. It looked like it was ending up with // in the URL with it in there. – stuckj Dec 04 '14 at 22:43
1

You might want to check

http://httpd.apache.org/docs/2.2/vhosts/mass.html

it deals with the DocumentRoot problem that you were experiencing.

Rule goes something like this

VirtualDocumentRoot /var/www/%1/

You can change the %1 for whatever suits you (http://httpd.apache.org/docs/2.0/mod/mod_vhost_alias.html)

Cheers

0

Some Questions:

You said "map internally" -- do you NOT want to use a redirect?

Are you using the same VirtualHost for gnome.bob.mysite.com and bob.mysite.com

Did you remember to create a ServerAlias for *.bob.mysite.com?


Here is a rough version that you could modify to work. It will capture the subdomain and requested URL, and do a redirect to the main domain with the subdomain as the first part of the path, followed by the requested path, followed by the query string.
ServerName www.mysite.com
ServerAlias *.mysite.com

RewriteCond %{HTTP_HOST} ^([a-zA-Z0-9-]+)\\.mysite.com$
RewriteRule ^/(.*)       http://www.mysite.com/%1/$1        [R=301,L]',    
gahooa
  • 131,293
  • 12
  • 98
  • 101
  • I definitely want an internal redirect. the whole purpose of this is to be able to use absolute paths on links, css, img srcs, etc. There is/will be a virtual host for .my-site.com with an alias for *..my-site.com, so any requested domain of .my-site.com or below will get picked up by that vhost – Jim Rubenstein Jul 22 '09 at 18:17
0

Have you tried using another rewrite rule to process the one before it?

RewriteEngine On

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

But I think your bigger problem is the fact that your server doesn't understand it is getting served under a different name.

It thinks it is running in the /gnome/ directory while the browser things it is running in the / directory. So any relative URL's that you have are going to cause issues.

What you need is a filter that will run all the URL's in your page through a processor and change them from /gnome/ to /.

Nick Berardi
  • 54,393
  • 15
  • 113
  • 135