Summary
The module mod_vhost_alias provides support for dynamically configured mass virtual hosting.
Virtual hosting
The term Virtual Host refers to the practice of maintaining more than one server on one machine or server instance, as differentiated by their apparent hostname (or server instance name). For example, it is often desirable for companies sharing a web server to have their own domains, with web servers accessible as www.company1.com and www.company2.com, without requiring the user to know extra path information.
HTTP Server (powered by Apache) supports two types of virtual hosting, they are IP-based Virtual Host and Name-based Virtual Host. As the term IP-based indicates, the server must have a different IP address for each IP-based virtual host. This can be achieved by the machine having several physical network connections, or by use of virtual interfaces that are supported by most modern operating systems.
While the approach with IP-based Virtual Hosts works well, it is not the most elegant solution, because a dedicated IP address is needed for every virtual host and is hard to implement on some machines. The HTTP/1.1 protocol contains a method for the server to identify what name it is being addressed as.
The benefits of using the name-based virtual host support is a practically unlimited number of servers, ease of configuration and use, and no additional hardware or software requirements. The main disadvantage is that the client must support this part of the protocol. The latest versions of most browsers (e.g. HTTP 1.1) do, but there are still old browsers (e.g. HTTP 1.0) in use that do not. This can cause problems, although a possible solution is addressed below.
Using non-IP virtual hosts
The notable difference between IP-based and name-based virtual host configuration is the NameVirtualHost directive that specifies an IP address that should be used as a target for name-based virtual hosts. For example, suppose that both www.domain.tld and www.otherdomain.tld point at the IP address 111.22.33.44. Simply add to one of the configuration files (most likely httpd.conf or srm.conf) code similar to the following:
NameVirtualHost 111.22.33.44 <VirtualHost 111.22.33.44> ServerName www.domain.tld DocumentRoot /www/domain </VirtualHost> <VirtualHost 111.22.33.44> ServerName www.otherdomain.tld DocumentRoot /www/otherdomain </VirtualHost>
Of course, any additional directives can (and should) be placed into the <VirtualHost> section. To make this work, make sure that the names www.domain.tld and www.otherdomain.tld are pointing to the IP address 111.22.33.44
Additionally, many servers may want to be accessible by more than one name. For example, the example server might want to be accessible as domain.tld, or www2.domain.tld, assuming the IP addresses pointed to the same server. In fact, one might want it so that all addresses at domain.tld were picked up by the server. This is possible with the ServerAlias directive, placed inside the <VirtualHost> section. For example:
ServerAlias domain.tld *.domain.tld
You might also need ServerAlias if you are serving local users who do not always include the domain name. For example, if local users are familiar with typing "www" or "www.example" then you will need to add ServerAlias www www.example. It isn't possible for the server to know what domain the client uses for their name resolution because the client doesn't provide that information in the request. The ServerAlias directive provides a means for different hostnames to point to the same virtual host.
Dynamic virtual hosting
A virtual host is defined by two pieces of information: its IP address, and the contents of the Host: header in the HTTP request. The dynamic mass virtual hosting technique is based on automatically inserting this information into the pathname of the file that is used to satisfy the request. This is done most easily using mod_vhost_alias.
A couple of things need to be `faked', that being specific parameters with incorrect parameter values, to make the dynamic virtual host look like a normal one. The most important is the server name which is used by HTTP Server to generate a self referencing URLs. It is configured with the ServerName directive, and it is available to CGIs via the SERVER_NAME environment variable. The actual value used at run time is controlled by the UseCanonicalName setting. With UseCanonicalName off the server name comes from the contents of the Host: header in the request. With UseCanonicalName DNS it comes from a reverse DNS lookup of the virtual host's IP address. The former setting is used for name-based dynamic virtual hosting, and the latter is used for IP-based hosting. If HTTP Server cannot work out the server name because there is no Host: header or the DNS lookup fails then the value configured with ServerName is used instead.
The other thing to `fake' is the document root (configured with DocumentRoot and available to CGIs via the DOCUMENT_ROOT environment variable). This setting is used by the core module when mapping URIs to filenames, but when the server is configured to do dynamic virtual hosting that job is taken over by the mod_vhost_alias module. If any CGIs or SSI documents make use of the DOCUMENT_ROOT environment variable they will therefore get a misleading value; there is not any way to change DOCUMENT_ROOT dynamically.
Motivation for dynamic virtual hosting
The techniques described here are of interest if your httpd.conf contains many <VirtualHost> sections that are substantially the same. For example:
NameVirtualHost 10.22.33.44 <VirtualHost 10.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 10.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> # comment line <VirtualHost 10.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 virtual host; however if you have very many virtual hosts then doing this is dubious anyway because it eats file descriptors. It is better to log to a pipe or a fifo and arrange for the process at the other end to distribute the logs to the customers (it can also accumulate statistics).
A request for http://www.example.isp.com/directory/file.html will be satisfied by the file:
/usr/local/apache/vhosts/isp.com/e/x/a/example/directory/file.html.
A more even spread of files can be achieved by hashing from the end of the name, for example:
VirtualDocumentRoot /usr/local/apache/vhosts/%3+/%2.-1/%2.-2/%2.-3/%2
The example request would come from /usr/local/apache/vhosts/isp.com/e/l/p/example/directory/file.html. Alternatively you might use:
VirtualDocumentRoot /usr/local/apache/vhosts/%3+/%2.1/%2.2/%2.3/%2.4+
The example request would come from /usr/local/apache/vhosts/isp.com/e/x/a/mple/directory/file.html.
Simple dynamic virtual hosts
This extract from httpd.conf implements the virtual host arrangement outlined in the Motivation section above, but in a generic fashion using mod_vhost_alias.
# get the server name from the Host: header UseCanonicalName off # this log format can be split per-virtual-host based on the first field LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon CustomLog logs/access_log vcommon # include the server name in the filenames used to satisfy requests VirtualDocumentRoot /www/hosts/%0/docs VirtualScriptAlias /www/hosts/%0/cgi-bin
This configuration can be changed into an IP-based virtual hosting solution by just turning UseCanonicalName off into UseCanonicalName DNS. The server name that is inserted into the filename is then derived from the IP address of the virtual host.
A virtually hosted homepages system
This is an adjustment of the above system tailored for an ISP's homepages server. Using a slightly more complicated configuration 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.
# all the preliminary stuff is the same as above, then # include part of the server name in the filenames VirtualDocumentRoot /www/hosts/%2/docs # single cgi-bin directory ScriptAlias /cgi-bin/ /www/std-cgi/
Use more than one virtual hosting system on the same server
With more complicated setups you can use HTTP Server's normal <VirtualHost> directives to control the scope of the various virtual hosting 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 conventional <VirtualHost> configuration sections.
UseCanonicalName off LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon <Directory /www/commercial> Options FollowSymLinks AllowOverride All </Directory> <Directory /www/homepages> Options FollowSymLinks AllowOverride None </Directory> <VirtualHost 10.22.33.44> ServerName www.commercial.isp.com CustomLog logs/access_log.commercial vcommon VirtualDocumentRoot /www/commercial/%0/docs VirtualScriptAlias /www/commercial/%0/cgi-bin </VirtualHost> <VirtualHost 10.22.33.45> ServerName www.homepages.isp.com CustomLog logs/access_log.homepages vcommon VirtualDocumentRoot /www/homepages/%0/docs ScriptAlias /cgi-bin/ /www/std-cgi/ </VirtualHost>
Directory name interpolation
All the directives in this module interpolate (insert) a string into a pathname. The interpolated string may either be the server name (see UseCanonicalName for more information) or the IP address of the virtual host on the server in dotted-quad format. The interpolation is controlled by specifiers inspired by UNIX® printf which have a number of formats:
Specifier | Description |
---|---|
%% | Insert a % sign |
%p | Insert the port number of the virtual host |
%N.M | Insert (part of) the interpolated string |
N and M are used to specify substrings of the interpolated string. N selects from the period separated components of the interpolated string, and M selects characters within whatever N has selected. M is optional and defaults to zero if it is not present. The period (.) must be present if and only if M is present. The interpretation is as follows:
N.M interpretation | Description |
---|---|
0 | The whole name. |
1 | The first part. |
2 | The second part. |
-1 | The last part. |
-2 | The next to last part. |
2+ | The second and all subsequent parts. |
-2+ | The next to last part and all preceding parts. |
1+ and -1+ | The same as 0 (zero). |
If N or M is greater than the number of parts available a single underscore is interpolated.
For a simple name-based virtual hosts you might use the following directives in your server configuration file:
UseCanonicalName off VirtualDocumentRoot /usr/local/www.example.isp.com/vhosts/%0 A request for http://www.example.com/directory/file.html will be satisfied by the file /usr/local/www.example.isp.com/vhosts/www.example.com/directory/file.html.
For a very large number of virtual hosts it is a good idea to arrange the files to reduce the size of the vhosts directory. To do this you might use the following in your configuration file:
UseCanonicalName off VirtualDocumentRoot /usr/local/www.example.isp.com/vhosts/%3+/%2.1/%2.2/%2.3/%2 A request for http://www.example.isp.com/directory/file.html will be satisfied by the file /usr/local/www.example.isp.com/isp.com/e/x/a/example/directory/file.html.
A more even spread of files can be achieved by hashing from the end of the name, for example:
VirtualDocumentRoot /usr/web/www.example.isp.com/vhosts/%3+/%2.-1/%2.-2/%2.-3/%2
The example request would come from /usr/web/www.example.isp.com/vhosts/isp.com/e/l/p/example/directory/file.html. Alternatively you might use:
VirtualDocumentRoot /usr/local/www.example.isp.com/vhosts/%3+/%2.1/%2.2/%2.3/%2.4+
The example request would come from /usr/web/www.example.isp.com/vhosts/isp.com/e/x/a/mple/directory/file.html. For IP-based virtual hosting you might use the following in your configuration file:
UseCanonicalName DNS VirtualDocumentRootIP /usr/local/www.example.isp.com/vhost/%1/%2/%3/%4/docs VirtualScriptAliasIP /usr/local/www.example.isp.com/vhost/%1/%2/%3/%4/cgi-bin
A request for http://www.example.isp.com/directory/file.html would be satisfied by the file /usr/local/www.example.isp.com/10/20/30/40/docs/directory/file.html if the IP address of www.example.com were 10.20.30.40. A request for http://www.example.isp.com/cgi-bin/script.pl would be satisfied by executing the program /usr/local/www.example.isp.com/10/20/30/40/cgi-bin/script.pl.
The LogFormat directives %V and %A are useful in conjunction with this module. See LogFormat for more information.
Directives
Module: mod_vhost_alias | |
Syntax: VirtualDocumentRoot interpolated-directory | |
Default: none | |
Context: server config, virtual host | |
Override: none | |
Origin: Apache | |
Usage Considerations: A LoadModule is required in the config file prior to using the directive. The statement should be as follows: LoadModule vhost_alias_module /QSYS.LIB/QHTTPSVR.LIB/QZSRCORE.SRVPGM | |
Example: See below. |
The VirtualDocumentRoot directive allows you to determine where the server will finds your documents based on the value of the server name. The result of expanding interpolated-directory is used as the root of the document tree in a similar manner to the DocumentRoot disabled. See DocumentRoot for more information.
If interpolated-directory is none then VirtualDocumentRoot is disabled. This directive cannot be used in the same context as VirtualDocumentRootIP. See VirtualDocumentRootIP for more information.
For example, a simple dynamic virtual host:
# LocalModule directive required LoadModule vhost_alias_module /QSYS.LIB/QHTTPSVR.LIB/QZSRCORE.SRVPGM # get the server name from the Host: header UseCanonicalName off # this log format can be split per-virtual-host based on the first field LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon CustomLog logs/access_log vcommon # include the server name in the filenames used to satisfy requests VirtualDocumentRoot /www/web/%0/docs
The next example is an adjustment of the above, system tailored for an ISP's homepage server. Using a slightly more complicated configuration 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:
# LocalModule directive required LoadModule vhost_alias_module /QSYS.LIB/QHTTPSVR.LIB/QZSRCORE.SRVPGM # get the server name from the Host: header UseCanonicalName off # include part of the server name in the filenames VirtualDocumentRoot /usr/web/hosts/%2/docs # single cgi-bin directory ScriptAlias /cgi-bin/ /usr/web/std-cgi/
Module: mod_vhost_alias | |
Syntax: VirtualDocumentRootIP interpolated-directory | |
Default: none | |
Context: server config, virtual host | |
Override: none | |
Origin: Apache | |
Usage Considerations: A LoadModule is required in the config file prior to using the directive. The statement should be as follows: LoadModule vhost_alias_module /QSYS.LIB/QHTTPSVR.LIB/QZSRCORE.SRVPGM | |
Example: See VirtualDocumentRoot. |
More complicated setups can use the server's normal <VirtualHost> directives to control the scope of the various virtual hosting configurations. For example, you could have one IP address for home page customers and another for commercial customers with the following directives. This can of course be combined with conventional <VirtualHost> configuration sections.
UseCanonicalName off LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon <Directory /usr/web/commercial> Options FollowSymLinks AllowOverride All </Directory> <Directory /usr/web/homepages> Options FollowSymLinks AllowOverride None </Directory> # LocalModule directive required LoadModule vhost_alias_module /QSYS.LIB/QHTTPSVR.LIB/QZSRCORE.SRVPGM <VirtualHost 10.22.33.44> ServerName www.commercial.isp.com CustomLog logs/access_log.commercial vcommon VirtualDocumentRoot /usr/web/commercial/%0/docs VirtualScriptAlias /usr/web/commercial/%0/cgi-bin </VirtualHost> <VirtualHost 10.22.33.45> ServerName www.homepages.isp.com CustomLog logs/access_log.homepages vcommon VirtualDocumentRoot /usr/web/homepages/%0/docs ScriptAlias /cgi-bin/ /usr/web/std-cgi/ </VirtualHost>
More efficient IP-based virtual hosting:
In the first example note that it is easy to turn it into an IP-based virtual hosting setup. Unfortunately that configuration is not very efficient because it requires a DNS lookup for every request. This can be avoided by laying out the filesystem according to the IP addresses themselves rather than the corresponding names and changing the logging similarly. HTTP Server will not usually need to work out the server name and a DNS lookup. For example:
# Get the server name from the reverse DNS of the IP address UseCanonicalName DNS # LocalModule directive required LoadModule vhost_alias_module /QSYS.LIB/QHTTPSVR.LIB/QZSRCORE.SRVPGM # include the IP address in the logs so they may be split LogFormat "%A %h %l %u %t \"%r\" %s %b" vcommon CustomLog logs/access_log vcommon # include the IP address in the filenames VirtualDocumentRootIP /usr/web/hosts/%0/docs VirtualScriptAliasIP /usr/web/hosts/%0/cgi-bin
The VirtualDocumentRootIP directive is like the VirtualDocumentRoot directive, except that it uses the IP address of the server end of the connection instead of the server name. See VirtualDocumentRoot for more information.
Module: mod_vhost_alias | |
Syntax: VirtualScriptAlias interpolated-directory | |
Default: none | |
Context: server config, virtual host | |
Override: none | |
Origin: Apache | |
Usage Considerations: A LoadModule is required in the config file prior to using the directive. The statement should be as follows: LoadModule vhost_alias_module /QSYS.LIB/QHTTPSVR.LIB/QZSRCORE.SRVPGM | |
Example: See below. |
Using more than one virtual hosting system on the same server instance:
More complicated setups use the server's normal <VirtualHost> directives to control the scope of the various virtual hosting configurations. For example, you could have one IP address for homepages customers and another for commercial customers with the following directives. This can of course be combined with conventional <VirtualHost> configuration sections.
UseCanonicalName off LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon <Directory/usr/web/commercial> Options FollowSymLinks AllowOverride All </Directory> <Directory /usr/web/homepages> Options FollowSymLinks AllowOverride None </Directory> # LocalModule directive required LoadModule vhost_alias_module /QSYS.LIB/QHTTPSVR.LIB/QZSRCORE.SRVPGM <VirtualHost 10.22.33.44> ServerName www.commercial.isp.com CustomLog logs/access_log.commercial vcommon VirtualDocumentRoot /usr/web/commercial/%0/docs VirtualScriptAlias /usr/web/commercial/%0/cgi-bin </VirtualHost> <VirtualHost 10.22.33.45> ServerName www.homepages.isp.com CustomLog logs/access_log.homepages vcommon VirtualDocumentRoot /usr/web/homepages/%0/docs ScriptAlias /cgi-bin/ /usr/web/std-cgi/ </VirtualHost>
VirtualScriptAlias /user/web/commercial/%0/cgi-bin
Module: mod_vhost_alias | |
Syntax: VirtualScriptAliasIP interpolated-directory | |
Default: none | |
Context: server config, virtual host | |
Override: none | |
Origin: Apache | |
Usage Considerations: A LoadModule is required in the config file prior to using the directive. The statement should be as follows: LoadModule vhost_alias_module /QSYS.LIB/QHTTPSVR.LIB/QZSRCORE.SRVPGM | |
Example: See VirtualScriptAlias. |
The VirtualScriptAliasIP directive is like the VirtualScriptAlias directive, except that it uses the IP address of the server end of the connection instead of the server name.