From c1c51cd783c35212ab764533b2afc82637b57e2a Mon Sep 17 00:00:00 2001
From: brian This document describes how to efficiently serve an arbitrary number
+of virtual hosts with Apache 1.3. Some familiarity with
+ The techniques described here are of interest if your
+Dynamically configured mass virtual hosting
+
+mod_rewrite
is
+useful.Contents:
+
+
+
+
+Motivation
+
+httpd.conf
contains hundreds of
+<VirtualHost>
sections that are substantially the
+same, for example:
+
+NameVirtualHost 111.22.33.44
+<VirtualHost 111.22.33.44>
+ ServerName www.customer-1.com
+ DocumentRoot /www/hosts/www.customer-1.com/docs
+ ScriptAlias /cgi-bin/ /www/hosts/www.customer-1.com/cgi-bin
+</VirtualHost>
+<VirtualHost 111.22.33.44>
+ ServerName www.customer-2.com
+ DocumentRoot /www/hosts/www.customer-2.com/docs
+ ScriptAlias /cgi-bin/ /www/hosts/www.customer-2.com/cgi-bin
+</VirtualHost>
+# blah blah blah
+<VirtualHost 111.22.33.44>
+ ServerName www.customer-N.com
+ DocumentRoot /www/hosts/www.customer-N.com/docs
+ ScriptAlias /cgi-bin/ /www/hosts/www.customer-N.com/cgi-bin
+</VirtualHost>
+
+
The basic idea is to replace all of the static
+<VirtualHost>
configuration with a mechanism that
+works it out dynamically. This has a number of advantages:
+
The main disadvantage is that you cannot have a different log file
+for each server; however if you have very many virtual hosts then
+doing this is dubious anyway because it eats file descriptors. It's
+better to log to a pipe or a fifo and arrange for the process at the
+other end to distribute the logs (and perhaps accumulate statistics,
+etc.). A LogFormat
directive that includes
+%v
for the virtual host makes it easy to do this.
All of the dynamic virtual hosts will either be configured as part
+of the main server configuration, or within a
+<VirtualHost>
section. For a simple (very uniform)
+setup, <VirtualHost>
sections aren't needed at all.
A couple of things need to be `faked' to make the dynamic virtual
+host look like a normal one. The most important is the server name
+(configured with ServerName
and available to CGIs via the
+SERVER_NAME
environment variable). The way it is
+determined is controlled by the UseCanonicalName
+directive: with UseCanonicalName off
the server name
+comes from the contents of the Host:
header in the
+request. If there is no Host:
header then the value
+configured with ServerName
is used instead.
The other one is the document root (configured with
+DocumentRoot
and available to CGIs via the
+DOCUMENT_ROOT
environment variable). This is used by the
+core module when mapping URIs to filenames, but in the context of
+dynamic virtual hosting its value only matters if any CGIs or SSI
+documents make use of the DOCUMENT_ROOT
environment
+variable. This is an Apache extension to the CGI specification and as
+such shouldn't really be relied upon, especially because this
+technique breaks it: there isn't currently a way of setting
+DOCUMENT_ROOT
dynamically.
The meat of the mechanism works via Apache's URI-to-filename
+translation API phase. This is used by a number of modules:
+mod_rewrite
,
+mod_alias
,
+mod_userdir
,
+and the core module.
+In the default configuration these modules are called in that order
+and given a chance to say that they know what the filename is. Most of
+these modules do it in a fairly simple fashion (e.g. the core module
+concatenates the document root and the URI) except for
+mod_rewrite
, which provides enough functionality to do
+all sorts of sick and twisted things (like dynamic virtual hosting).
+Note that because of the order in which the modules are called, using
+a mod_rewrite
configuration that matches any URI means
+that the other modules (particularly mod_alias
) will
+cease to function. The examples below show how to deal with this.
The dynamic virtual hosting idea is very simple: use the +server name as well as the URI to determine the corresponding +filename.
+ + +This extract from httpd.conf
implements the virtual
+host arrangement outlined in the Motivation
+section above, but in a generic fashion.
The first half shows some other configuration options that are
+needed to make the mod_rewrite
part work as expected; the
+second half uses mod_rewrite
to do the actual work. Some
+care is taken to do a per-dynamic-virtual-host equivalent of
+ScriptAlias
.
+# dynamic ServerName +UseCanonicalName Off + +# splittable logs +LogFormat "%v %h %l %u %t \"%r\" %s %b" vcommon +CustomLog logs/access_log vcommon + +<Directory /www/hosts> + # ExecCGI is needed here because we can't force + # CGI execution in the way that ScriptAlias does + Options FollowSymLinks ExecCGI +</Directory> + +# now for the hard bit + +RewriteEngine On + +# a ServerName derived from a Host: header may be any case at all +RewriteMap lowercase int:tolower + +## deal with normal documents first: +# allow Alias /icons/ to work - repeat for other aliases +RewriteCond %{REQUEST_URI} !^/icons/ +# allow CGIs to work +RewriteCond %{REQUEST_URI} !^/cgi-bin/ +# do the magic +RewriteRule ^/(.*)$ /www/hosts/${lowercase:%{SERVER_NAME}}/docs/$1 + +## and now deal with CGIs - we have to force a MIME type +RewriteCond %{REQUEST_URI} ^/cgi-bin/ +RewriteRule ^/(.*)$ /www/hosts/${lowercase:%{SERVER_NAME}}/cgi-bin/$1 [T=application/x-httpd-cgi] + +# that's it! ++ + +
This is an adjustment of the above system tailored for an ISP's
+homepages server. Using slightly more complicated rewriting rules we
+can select substrings of the server name to use in the filename so
+that e.g. the documents for www.user.isp.com are found in
+/home/user/
. It uses a single cgi-bin
+directory instead of one per virtual host.
+RewriteEngine on + +RewriteMap lowercase int:tolower + +# allow CGIs to work +RewriteCond %{REQUEST_URI} !^/cgi-bin/ + +# check the hostname is right so that the RewriteRule works +RewriteCond ${lowercase:%{HTTP_HOST}} ^www\.[a-z-]+\.isp\.com$ + +# concatenate the virtual host name onto the start of the URI +# the [C] means do the next rewrite on the result of this one +RewriteRule ^(.+) ${lowercase:%{HTTP_HOST}}$1 [C] + +# now create the real file name +RewriteRule ^www\.([a-z-]+)\.isp\.com/(.*) /home/$1/$2 + +# define the global CGI directory +ScriptAlias /cgi-bin/ /www/std-cgi/ ++ + +
This arrangement uses a separate configuration file to specify the +translation from virtual host to document root. This provides more +flexibility but requires more configuration.
+ +The vhost.map
file contains something like this:
+
+www.customer-1.com /www/customers/1 +www.customer-2.com /www/customers/2 +# ... +www.customer-N.com /www/customers/N ++ + +
The http.conf
contains this:
+
+RewriteEngine on + +RewriteMap lowercase int:tolower + +# define the map file +RewriteMap vhost txt:/www/conf/vhost.map + +# deal with aliases as above +RewriteCond %{REQUEST_URI} !^/icons/ +RewriteCond %{REQUEST_URI} !^/cgi-bin/ +RewriteCond ${lowercase:%{SERVER_NAME}} ^(.+)$ +# this does the file-based remap +RewriteCond ${vhost:%1} ^(/.*)$ +RewriteRule ^/(.*)$ %1/docs/$1 + +RewriteCond %{REQUEST_URI} ^/cgi-bin/ +RewriteCond ${lowercase:%{SERVER_NAME}} ^(.+)$ +RewriteCond ${vhost:%1} ^(/.*)$ +RewriteRule ^/(.*)$ %1/cgi-bin/$1 ++ + + +
With more complicated setups, you can use Apache's normal
+<VirtualHost>
directives to control the scope of
+the various rewrite configurations. For example, you could have one IP
+address for homepages customers and another for commercial customers
+with the following setup. This can of course be combined with
+convential <VirtualHost>
configuration
+sections.
+UseCanonicalName Off + +LogFormat "%v %h %l %u %t \"%r\" %s %b" vcommon +CustomLog logs/access_log vcommon + +<Directory /www/commercial> + Options FollowSymLinks ExecCGI + AllowOverride All +</Directory> + +<Directory /www/homepages> + Options FollowSymLinks + AllowOverride None +</Directory> + +<VirtualHost 111.22.33.44> + ServerName www.commercial.isp.com + + RewriteEngine On + RewriteMap lowercase int:tolower + + RewriteCond %{REQUEST_URI} !^/icons/ + RewriteCond %{REQUEST_URI} !^/cgi-bin/ + RewriteRule ^/(.*)$ /www/commercial/${lowercase:%{SERVER_NAME}}/docs/$1 + + RewriteCond %{REQUEST_URI} ^/cgi-bin/ + RewriteRule ^/(.*)$ /www/commercial/${lowercase:%{SERVER_NAME}}/cgi-bin/$1 [T=application/x-httpd-cgi] +</VirtualHost> + +<VirtualHost 111.22.33.45> + ServerName www.homepages.isp.com + + RewriteEngine on + RewriteMap lowercase int:tolower + + RewriteCond %{REQUEST_URI} !^/cgi-bin/ + + RewriteCond ${lowercase:%{HTTP_HOST}} ^www\.[a-z-]+\.isp\.com$ + RewriteRule ^(.+) ${lowercase:%{HTTP_HOST}}$1 [C] + RewriteRule ^www\.([a-z-]+)\.isp\.com/(.*) /www/homepages/$1/$2 + + ScriptAlias /cgi-bin/ /www/std-cgi/ +</VirtualHost> ++ + +