This chapter explains how to host multiple websites with a single instance of the Apache server, using both IP-address–based and name-based virtual hosting. It also covers other topics related to providing hosting for multiple users, such as home directories and per-directory configuration files.
Virtual hosting is a feature provided by most modern web servers that allows you to serve multiple websites, each one identified by one or more domains, using a single instance of a server. This provides for a centralized administration and an efficient use of system resources. Many commercial web hosting providers are able to provide service to hundreds of customers using a single server instance instead of having hundreds of Apache servers running in the background.
The easiest way to provide virtual hosting is based on the IP address/port combination that the client connects to. We can configure Apache to support IP-based virtual hosting using <VirtualHost>
sections. Each <VirtualHost>
contains configuration directives that will be applied for requests addressed to the IP address (and optionally port number) specified in the opening tag. Of course, the server Apache is running on must have been configured with those IP addresses.
If you are listening on nonstandard ports, make sure to provide a Listen
directive for each one of them. Just listing them on the <VirtualHost>
section will not cause Apache to listen for request in those ports.
IP-based virtual hosting has the drawback of having to assign a different IP address to each different virtual host.
The example in Listing 5.1 shows three IP-based virtual hosts serving content for three websites: www.example.com, a staging version of www.example.com, and www.example.net. The ServerName
directive inside each container will be used for constructing self-referential URLs. The DocumentRoot
directive specifies a different location for the website’s content for each virtual host. It is also possible to log requests and errors for each virtual host to a different file. This can be done by placing logging directives such as TransferLog
and ErrorLog
inside the virtual host container, as explained in Chapter 3.
The addresses and ports listed inside the opening tag of a <VirtualHost>
definition will not have any effect on what addresses or ports Apache listens to, so you still need to provide the appropriate Listen
directives. If no port is specified in a <VirtualHost>
definition, the one specified in the most recent Apache directive will be used. It is also possible to specify a wildcard “*
” to listen for requests in all ports that Apache is listening in, as shown in the example.net virtual host.
Example 5.1. Configuring IP-Based Virtual Hosts
Listen 8080 Listen 80 <VirtualHost 192.168.200.2> ServerName www.example.com DocumentRoot /usr/local/apache/sites/example.com </VirtualHost> <VirtualHost 192.168.200.2:8080> ServerName www.example.com DocumentRoot /usr/local/apache/sites/staging </VirtualHost> <VirtualHost 192.168.200.4:*> ServerName www.example.net DocumentRoot /usr/local/apache/sites/example.net </VirtualHost>
As seen in the previous sections, IP virtual hosting requires a different IP address for each website. This creates quite a few problems if you need to host a great number of websites or you cannot get or do not want to pay for more than one IP address. An example where this would be the case would be if you wanted to run several personal websites out of your own server at the end of a DSL line.
Name-based virtual hosting takes advantage of the fact that most browsers in widespread use (and almost all recent ones) transmit a Host:
header in their HTTP request. This is a requirement of the HTTP/1.1 protocol, but is also present in most implementations of HTTP/1.0. Thus, we can decide which information to present to the user based on data from the HTTP request, rather than on data from the connection itself. This allows several virtual hosts to share the same IP address and port combination.
The configuration for named virtual hosts is similar to IP virtual hosts. The example in Listing 5.2 shows two virtual hosts sharing the 192.168.200.2 IP address.
Apache will decide to which virtual host to “route” the request based on the value of the Host:
header of the HTTP request. It will be compared for a match with the hostname provided by ServerName
and any additional hostnames provided by the ServerAlias
directives, which are optional.
Example 5.2. Configuring Name-based Virtual Hosts
Listen 80 NameVirtualHost 192.168.200.2 <VirtualHost 192.168.200.2> ServerName www.example.com ServerAlias example.com web.example.com DocumentRoot /usr/local/apache/sites/example.com </VirtualHost> <VirtualHost 192.168.200.2> ServerName www.example.net DocumentRoot /usr/local/apache/sites/example.net </VirtualHost>
The NameVirtualHost
directive is required to tell Apache that a particular IP address will be used for name-based virtual hosts. You can tell Apache to use any available IP address for name-based virtual hosting with
NameVirtualHost *
Of course, your DNS servers need to be configured properly so the domains www.example.com, example.com, and web.example.com resolve to the 192.168.200.2 address.
If a request does not match any virtual host then it will be served by the main server in the case of IP-based virtual hosting. In the case of name-based virtual hosting, the first name-based virtual host will be used. See the next couple of sections for details on how to configure a default catch-all virtual host.
As mentioned in the previous section, the first virtual host present in the configuration file will answer requests for domains that are not explicitly handled by other virtual hosts. If you host multiple websites, it can be useful to set up that virtual host so it returns a page that either provides a list of available websites in the machine or explains why that particular website is not recognized. You can do so by placing such a file (default.html in the example in Listing 5.3) in the document root and redirecting all requests to it with an AliasMatch
directive. You can achieve a similar effect replacing it with an ErrorDocument
directive:
ErrorDocument 404 /default.html
Or you can even send users directly to one of your other websites with a Redirect
directive.
RedirectMatch /* http://www.example.com
<VirtualHost _default_ > ServerName default.example.com DocumentRoot /usr/local/apache/sites/default </VirtualHost>
The special _default_
syntax allows you to define a virtual host that will serve requests for addresses and port combinations not covered by other virtual hosts. You can also specify a port number in combination with the _default_
keyword, as in the following example, taken from the default Apache mod_ssl
configuration. It specifies a virtual host that will listen for requests on that particular port, in all addresses not explicitly handled by other virtual hosts:
It is possible to mix and match IP-based and name-based virtual hosts, as shown in Listing 5.4. Instead of using NameVirtualHost *
, you will need to provide separate NameVirtualHost
directives for each IP address that will be associated with name-based virtual hosts. This example shows two name-based virtual hosts associated with the 192.168.200.2 IP address and one IP-based virtual host associated with IP address 192.168.200.4.
Example 5.4. Mixing IP-based and Name-based Virtual Hosting
NameVirtualHost 192.168.200.2 <VirtualHost 192.168.200.2> ServerName www.example.com DocumentRoot /usr/local/apache/sites/example.com </VirtualHost> <VirtualHost 192.168.200.2> ServerName staging.example.com DocumentRoot /usr/local/apache/sites/staging </VirtualHost> <VirtualHost 192.168.200.4> ServerName www.example.net DocumentRoot /usr/local/apache/sites/example.net </VirtualHost>
You can invoke the httpd
binary with the -S
option, as shown in Listing 5.5, and Apache will parse the configuration file. After processing all of the virtual host related information, it will present you with information about each configured virtual host and default host values. This is a very handy tool for debugging complex virtual host setups.
Example 5.5. Checking the Virtual Host Configuration
# httpd -S VirtualHost configuration: wildcard NameVirtualHosts and _default_ servers: *:* is a NameVirtualHost default server example.com (/usr/local/www/conf/httpd.conf:1055) port * namevhost example.com (/usr/local/www/conf/httpd.conf:1055) port * namevhost example.org (/usr/local/www/conf/httpd.conf:1082) port * namevhost example.net (/usr/local/www/conf/httpd.conf:1094) Syntax Ok
The short answer is that SSL cannot be used with name-based virtual hosts, as there are currently no mainstream browsers that support it. See the related section in Chapter 7 for a more in-depth explanation.
UseCanonicalName Off VirtualDocumentRoot /usr/local/apache/vhosts/%0 VirtualScriptAlias /usr/local/apache/vhosts/%0/cgi-bin
If you maintain a great number of virtual hosts, it may be desirable to use a different approach for virtual hosting. This is particularly true for ISPs that host thousands of customers, as it would require entering details for each one of the virtual hosts in the configuration file and restarting the server each time a change is required.
The mod_virtualhost_alias
allows you to set up a different document root for each virtual host dynamically. This means that the request is mapped to a certain path on the file system based on information from the request itself, such as the IP address or the hostname. This example maps requests for a particular hostname to a path in the file system that includes that hostname (represented by the %0
in the path). Similarly, the VirtualScriptAlias
directive allows execution of CGI scripts in a directory path based on the hostname referred to by the request. If a user sends a request for /manual/index.html
to the www.example.com host, this directive will map that to /usr/local/apache/vhosts/www.example.com/manual/index.html
.
In a similar manner, you can map IP addresses instead of hostnames, for IP-based virtual hosting using the VirtualDocumentRootIP
and VirtualScriptAliasIP
directives.
You can decide to map requests based only on parts of the hostname or IP address or based on the port of the request. For that, you can use different %-based sequences, such as %p
for the port number, or %1
for the first part of the domain, %2
for the second, and so on.
The mod_vhost_alias
module is probably one of the most popular mass virtual host modules, due to the fact that is bundled with Apache. There are, however, a number of alternatives such as the following:
mod_vhost_ldap
: An Apache 2 module that allows you to store virtual host information inside an LDAP directory. It can be downloaded from http://alioth.debian.org/projects/modvhostldap/.
mod_vhost_dbi
: This module allows you to store virtual host configuration inside a SQL database and provides a great amount of flexibility. It runs on Apache 2 and can be obtained from http://www.outoforder.cc/projects/apache/mod_vhost_dbi/.
Chapter 11 covers a number of Multi-Processing Modules (MPMs), such as mod_perchild
, that allow you to run different virtual hosts under different user ids.
An issue related to hosting multiple websites is that of providing hosting services for multiple clients. If the number of clients is significant, you may want to use per-directory configuration files. Per-directory configuration files are usually called htaccess
files because they used to be used mostly for access control tasks. When this functionality is enabled, Apache will look for special configuration files in all directories leading to the file being requested. For example, if Apache receives a request for /usr/local/apache2/htdocs/index.html
, it will look for per-directory configuration files in the /
, /usr/
, /usr/local/
, /usr/local/apache2
, and /usr/local/apache2/htdocs
directories, in that order.
If found, the content for these configuration files is processed and merged with the main configuration from httpd.conf
read at startup time. This is quite convenient for the system administrator, as it can allow users to self-manage their configurations. Also, since the files are parsed on-the-fly, the server does not need to be restarted for each change. On the downside, this has a performance penalty. Apache must perform expensive disk operations looking for these files in every request, even if the files do not exist.
The directive AccessFilename
allows you to provide a list of filenames that Apache will look for when looking for per-directory configuration files.
If .htaccess
is present in the Context:
field in the directive reference syntax description of the Apache documentation, it means that directive can be placed in per-directory configuration files.
The AllowOverride
directive allows you to control the kind of configuration directives that can appear in per-directory configuration files. For example, you can let users change directory-indexing directives but not those related to authorization. Possible values are
Authconfig
: Authorization directives
FileInfo
: Directives controlling document types
Indexes
: Directives controlling directory indexing
Limit
: Host access control directives
Options
: Directives controlling specific directory features
All
: All directives belonging to above groups can be used
None
: Disable per-directory configuration files for that directory tree
<Directory /> AllowOverride None </Directory>
If you do not have a use for per-directory configuration files, you can disable this functionality altogether with the configuration shown here. This will increase the security and performance of the server, at the cost of the flexibility and convenience provided by these files.
18.191.233.205