Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I'd like to set up an environment where Apache virtual hosts can be dynamically created without reloading the configuration.

I can do this with mod_vhost_alias, I set up my default virtual host something like this

<VirtualHost *>
  UseCanonicalName Off
  VirtualDocumentRoot /var/www/sandboxes/domains/%0
  ServerName catchall.host
</VirtualHost>

That works just fine, but if a request is made for a hostname which isn't currently set up, I get a 404 Not Found error.

What I'd really like to do is only have this VirtualHost kick in only if the document root exists, otherwise have it try to match another vhost (in other words, make the presence of the the VirtualDocumentRoot work in the same way as using a ServerAlias)

I tried making this the second vhost, with the first vhost just handling all requests, but this didn't work - requests for domains where a VirtualDocumentRoot was configured were falling through to the default vhost.

So, how can I have dynamically configured vhosts, but with a fallback to another vhost for any which aren't configured yet?

share|improve this question

2 Answers 2

up vote 5 down vote accepted

I found a workaround which works for me.

I can use an ErrorDocument to pick up the 404 Error in a PHP script. At first, that seemed problematic. If there's no DocumentRoot, where will the script live?

I could use a URL for the error message, served from a different domain. However, in testing I found no way of knowing what the originally requested domain was.

The answer was to Alias a directory and serve the errors out of that, so my vhost looks like this

<VirtualHost *>
  UseCanonicalName Off
  VirtualDocumentRoot /var/www/sandboxes/domains/%0
  ServerName catchall.host
  Alias /errors /var/www/default/errors/
  ErrorDocument 404 /errors/notfound.php
</VirtualHost>

Now, when an unconfigured domain is requested, the script at /var/www/default/errors/notfound.php is invoked instead. This script can check $_SERVER['HTTP_HOST'] to see what domain was requested. If it is actually configured, then we have a regular 404. If it's not configured, we can display some alternate error message. In my case, it's where I show a UI to help set the vhost up.

share|improve this answer
    
Wouldn't that throw a 404 as the status for every request to the default? –  Kyle Mar 5 '12 at 3:15
1  
The error handler is only invoked if the VirtualDocumentRoot doesn't exist (or it really was a 404, but the notfound.php can easily tell the difference). –  Paul Dixon Mar 5 '12 at 9:42

I found your question when Googling. I had exactly the same problem and applied the fix as described in Paul's answer. However, for my complex web app, I wasn't happy with routing all requests trough one single notfound.php.

In the end, I managed to fix the problem without external scripts, only by editing my VirtualHost config.

At first, my VirtualHost was configured like this:

<VirtualHost *:80> Usecanonicalname Off Virtualdocumentroot /mnt/ramdisk/www/cms-%-3.0-development/ </VirtualHost>

I had URLs like client1.domainname.com, client2.domainname.com and whatever.domainname.com

which resolved to /mnt/ramdisk/www/cms-client1-development/, /mnt/ramdisk/www/cms-client2-development/ and /mnt/ramdisk/www/cms-whatever-development/

However, an URL like nonexistent.domainname.com would give me a 404 because the directory /mnt/ramdisk/www/cms-nonexistent-development/ did not exist. I wanted these subdomains to use the directory /mnt/ramdisk/www/cms-default-development/

I fixed this by using ModRewrite and ModProxy:

<VirtualHost *:80> Usecanonicalname Off Virtualdocumentroot /mnt/ramdisk/www/cms-%-3.0-development/ RewriteEngine on RewriteCond %{HTTP_HOST} ^(.*)\.domainname\.com$ [NC] RewriteCond /mnt/ramdisk/www/cms-%1-development/ !-d RewriteRule (.*) http://default.domainname.com/$1 [P,L] </VirtualHost>

What this does is: grab the subdomain (the part before .domainname.com), insert that into the path (the %1) and proxy requests to the default URL only if the directory doesn't exist.

By using a proxy, the process is transparent and the user thinks he's visiting http://nonexistent.domainname.com, while he actually views the content from http://default.domainname.com/.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.