Chapter 4. Virtual Hosts
A web server system supports multiple web sites in a way similar to a person who responds to her given name, as well as her nickname. In the Apache configuration file, each alternate identity, and probably the “main” one as well, is known as a virtual host (sometimes written as vhost) identified with a <VirtualHost> container directive. Depending on the name used to access the web server, Apache responds appropriately, just as someone might answer differently depending on whether she is addressed as “Miss Jones” or “Hey, Debbie!” If you want to have a single system support multiple web sites, you must configure Apache appropriately.
There are two different types of virtual host supported by Apache. The first type, called address-based or IP-based, is tied to the numeric network address used to reach the system. Bruce Wayne never answered the parlour telephone with “Batman here!” nor did he answer the phone in the Batcave by saying, “Bruce Wayne speaking.” However, it’s the same person answering the phone, just as it’s the same web server receiving the request.
The other type of virtual host is name-based, because the server’s response depends on what it is called. To continue the telephone analogy, consider an apartment shared by multiple roommates; you call the same number whether you want to speak to Dave, Joyce, Amaterasu, or George. Just as multiple people may share a single telephone number, multiple web sites can share the same IP address. However, all IP addresses shared by multiple Apache virtual hosts need to be declared with a NameVirtualHost directive.
In the most simple of Apache configurations, there are no virtual hosts. Instead, all of the directives in the configuration file apply universally to the operation of the server. The environment defined by the directives outside any <VirtualHost> containers is sometimes called the default server or perhaps the global server. There is no official name for it, but it can become a factor when adding virtual hosts to your configuration.
But what happens if you add a <VirtualHost> container to such a configuration? How are those directives outside the container interpreted, and what is their effect on the virtual host?
The answer is not a simple one: essentially, the effect is specific to each configuration directive. Some get inherited by the virtual hosts, some get reset to a default value, and some pretend they’ve never been used before. You’ll need to consult the documentation for each directive to know for sure.
There are two primary forms of virtual hosts: IP-based virtual hosts, where each virtual host has its own unique IP address; and name-based virtual hosts, where more than one virtual host runs on the same IP address but with different names. This chapter will show you how to configure each one and how to combine the two on the same server. You’ll also learn how to fix common problems that occur with virtual hosts.
4.1. Setting Up Name-Based Virtual Hosts
Solution
Use the NameVirtualHost * directive in conjunction with <VirtualHost> sections:
ServerName 127.0.0.1 NameVirtualHost * <VirtualHost *> ServerName TheSmiths.name DocumentRoot "C:/Apache/Sites/TheSmiths" </VirtualHost> <VirtualHost *> ServerName JohnSmith.name DocumentRoot "C:/Apache/Sites/JustJohnSmith" </VirtualHost>
Discussion
With IP addresses increasingly hard to come by, name-based virtual hosting is the most common way to run multiple web sites on the same Apache server. The previous recipe works, for most users, in most virtual hosting situations.
The *
in the previous rules means that the
specified hosts run on all addresses. For a machine with only a
single address, this means that it runs on that address but will also
run on the loopback
, or localhost
address. Thus if you are sitting at the physical server system, you
can view the web site.
The argument to the <VirtualHost> container directive is the same as the argument to the NameVirtualHost directive. Putting the hostname here may ignore the virtual host on server startup, and requests to this virtual host may unexpectedly go somewhere else. If your name server is down or otherwise unresponsive at the time that your Apache server is starting up, then Apache can’t match the particular <VirtualHost> section to the NameVirtualHost directive to which it belongs.
Requests for which there is not a virtual host listed will go to the
first virtual host listed in the configuration file. In the case of
the previous example, hostnames that are not explicitly mentioned in
one of the virtual hosts will be served by the
TheSmiths.name
virtual host.
It is particularly instructive to run httpd -S and observe the virtual host configuration as Apache understands it, to see if it matches the way that you understand it. httpd -S returns the virtual host configuration, showing which hosts are name-based, which are IP-based, and what the defaults are.
Multiple names can be listed for a particular virtual host using the ServerAlias directive, as shown here:
ServerName TheSmiths.name ServerAlias www.TheSmiths.name Smith.Family.name
It is important to understand that virtual hosts render the server listed in the main body of your configuration file no longer accessible—you must create a virtual host section explicitly for that host. List this host first, if you want it to be the default server.
Adding name-based virtual hosts to your Apache configuration does not magically add entries to your DNS server. You must still add records to your DNS server so that the names resolve to the IP address of the server system. When users type your server name(s) into their browser location bars, their computers first contact a DNS server to look up that name and resolve it to an IP address. If there is no DNS record, then their browsers can’t find your server.
For more information on configuring your DNS server, consult the documentation for the DNS software you happen to be running, or talk to your ISP if you’re not running your own DNS server.
See Also
4.2. Designating One Name-Based Virtual Host as the Default
Problem
You want all requests, whether they match a virtual host or use an IP address, to be directed to a default host, possibly with a “host not found” error message.
Solution
Add the following <VirtualHost> section, and list it before all of your other ones:
<VirtualHost *> ServerName default DocumentRoot /www/htdocs ErrorDocument 404 /site_list.html </VirtualHost>
Discussion
Note that this recipe is used in the context of name-based virtual
hosts, so it is assumed that you have other virtual hosts that are
also using the <VirtualHost
*> notation, and that there is also an
accompanying NameVirtualHost
*
appearing above them. We have used the default
name for clarity; you can call it whatever you want.
Setting the ErrorDocument 404 to a list of the available sites on the server directs the user to useful content, rather than leaving him stranded with an unhelpful 404 error message. You may wish to set DirectoryIndex to the site list as well, so that users who go directly to the front page of this site also get useful information.
It’s a good idea to list explicitly all valid hostnames either as ServerNames or ServerAliases, so that nobody ever winds up at the default site. However, if someone accesses the site directly by IP address, or if a hostname is added to the address in question before the appropriate virtual host is created, the user still gets useful content.
See Also
4.3. Setting Up Address-Based Virtual Hosts
Problem
You have multiple IP addresses assigned to your system, and you want to support one web site on each.
Solution
Create a virtual host section for each IP address you want to list on:
ServerName 127.0.0.1 <VirtualHost 10.0.0.1> ServerName TheSmiths.name DocumentRoot "C:/Apache/Sites/TheSmiths" </VirtualHost> <VirtualHost 10.0.0.2> ServerName JohnSmith.name DocumentRoot "C:/Apache/Sites/JustJohnSmith" </VirtualHost>
Discussion
The virtual hosts defined in this example catch all requests to the specified IP addresses, regardless of what hostname is used to get there. Requests to any other IP address not listed go to the virtual host listed in the main body of the configuration file.
The ServerName specified is used as the primary
name of the virtual host, when needed, but is not used in the process
of mapping a request to the correct host. Only the IP address is
consulted to figure out which virtual host to serve requests from,
not the Host
header field.
See Also
4.4. Creating a Default Address-Based Virtual Host
Problem
You want to create a virtual host to catch all requests that don’t map to one of your address-based virtual hosts.
Solution
Use the _default_ keyword to designate a default host:
<VirtualHost _default_> DocumentRoot /www/htdocs </VirtualHost>
Discussion
The _default_ keyword creates a virtual host that catches all requests for any address:port combinations for which there is not a virtual host configured.
The _default_ directive may be used in conjunction with a particular port number, such as:
<VirtualHost _default_:443>
Using this syntax means that the specified virtual host catches all requests to port 443, on all addresses for which there is not an explicit virtual host configured. This is the usual way to set up SSL, which you see in the default SSL configuration file.
_default_ typically does not work as people expect in the case of name-based virtual hosts. It does not match names for which there are no virtual host sections, only address:port combinations for which there are no virtual hosts configured. If you wish to create a default name-based host, see Recipe 4.2.
See Also
4.5. Mixing Address-Based and Name-Based Virtual Hosts
Problem
You have multiple IP addresses assigned to your system, and you want to support more than one web site on each address.
Solution
Provide a NameVirtualHost directive for each IP address, and proceed as you did with a single IP address:
ServerName 127.0.0.1 NameVirtualHost 10.0.0.1 NameVirtualHost 10.0.0.2 <VirtualHost 10.0.0.1> ServerName TheSmiths.name DocumentRoot "C:/Apache/Sites/TheSmiths" </VirtualHost> <VirtualHost 10.0.0.1> ServerName JohnSmith.name DocumentRoot "C:/Apache/Sites/JustJohnSmith" </VirtualHost> <VirtualHost 10.0.0.2> ServerName TheFergusons.name DocumentRoot "C:/Apache/Sites/TheFergusons" </VirtualHost> <VirtualHost 10.0.0.2> ServerName DoriFergusons.name DocumentRoot "C:/Apache/Sites/JustDoriFerguson" </VirtualHost>
Discussion
Using the address of the server, rather than the wildcard
*
argument, makes the virtual hosts listen only to
that IP address. However, you should notice that the argument to
<VirtualHost> still must match the argument
to the NameVirtualHost with which they are
connected.
See Also
4.6. Mass Virtual Hosting with mod_vhost_alias
Solution
Use VirtualDocumentRoot and VirtualScriptAlias provided by mod_vhost_alias .
VirtualDocumentRoot /www/vhosts/%-1/%-2.1/%-2/htdocs VirtualScriptAlias /www/vhosts/%-1/%-2.1/%-2/cgi-bin
Discussion
This recipe uses directives from mod_vhost_alias , which you may not have installed when you built Apache, as it is not one of the modules that is enabled by default.
These directives map requests to a directory built up from pieces of the hostname that was requested. Each of the variables represents one part of the hostname, so that each hostname is be mapped to a different directory.
In this particular example, requests for content from www.example.com is served from the directory /www/vhosts/com/e/example/htdocs, or from /www/vhosts/com/e/example/cgi-bin (for CGI requests). The full range of available variables is shown in Table 4-1.
Variable |
Meaning |
%% |
insert a % |
%p |
insert the port number of the virtual host |
%M.N |
insert (part of) the name |
M and N may have positive or negative integer values, which have the following meanings (see Table 4-2).
Value |
Meaning |
0 |
The whole name |
1 |
The first part of the name |
-1 |
The last part of the name |
2 |
The second part of the name |
-2 |
The next-to-last part of the name |
2+ |
The second, and all following, parts |
-2+ |
The next-to-last, and all proceeding, parts |
When the value is placed in the first part of the argument—in the M part of %M.N—it refers to parts of the hostname itself. When used in the second part—the N—refers to a particular letter from that part of the hostname. For example, in hostname www.example.com, the meanings of the variables are as shown in Table 4-3.
Value |
Meaning |
%0 |
www.example.com |
%1 |
www |
%2 |
example |
%3 |
com |
%-1 |
com |
%-2 |
example |
%-3 |
www |
%-2.1 |
e |
%-2.2 |
x |
%-2.3+ |
ample |
Depending on the number of virtual hosts, you may wish to create a directory structure subdivided alphabetically by domain name, by top-level domain, or simply by hostname.
4.7. Mass Virtual Hosting Using Rewrite Rules
Problem
Although there is a module—mod_vhost_alias—which is explicitly for the purpose of supporting large numbers of virtual hosts, it is very limiting and requires that every virtual host be configured exactly the same way. You want to support a large number of vhosts, configured dynamically, but, at the same time, you want to avoid mod_vhost_alias.
Solution
Use directives from mod_rewrite to map to a directory based on the hostname:
RewriteEngine on RewriteCond %{HTTP_HOST} ^(www\.)?([^.]+)\.com$ RewriteRule ^(.*)$ /home/%2$1
Discussion
mod_vhost_alias is useful, but it is best for settings where each virtual host is identical in every way but hostname. Using mod_vhost_alias precludes the use of other URL-mapping modules, such as mod_userdir, mod_rewrite, and mod_alias, and it can be very restrictive. Using mod_rewrite is less efficient, but it is more flexible.
For example, when using mod_vhost_alias, you must do all of your hosts with mod_vhost_alias; whereas with this alternate approach, you can do some of your hosts using the rewrite rules and others using conventional virtual host configuration techniques.
The directives in the Solution map requests for www.something.com (or without the www) to the directory /home/something.
4.8. SSL and Name-Based Virtual Hosts
Solution
In most common implementations of SSL, you are limited to one SSL host per address and port number. Thus, either you need to have a unique IP address for each SSL host or run them on alternate ports to get more than one on a particular IP address:
Listen 443 Listen 444 <VirtualHost 10.0.1.2:443> ServerName secure1.example.com DocumentRoot /www/vhosts/secure1 SSLEngine On SSLCertificateFile /www/conf/ssl/secure1.crt SSLCertificateKeyFile /www/conf/ssl/secure1.key </VirtualHost> <VirtualHost 10.0.1.3:443> ServerName secure2.example.com DocumentRoot /www/vhosts/secure2 SSLEngineOn SSLCertificateFile /www/conf/ssl/secure2.crt SSLCertificateKeyFile /www/conf/ssl/secure2.key </VirtualHost> <VirtualHost 10.0.1.3:444> ServerName secure3.example.com DocumentRoot /www/vhosts/secure3 SSLEngineOn SSLCertificateFile /www/conf/ssl/secure3.crt SSLCertificateKeyFile /www/conf/ssl/secure3.key </VirtualHost>
Discussion
The limitation that restricts you to one SSL host per IP address is not a limitation imposed by Apache but by the way that SSL works. When the browser connects to the server, the first thing that it does is negotiate for a secure connection. During this process, the server sends its certificate to the client, which indicates that the rest of the transaction will be encrypted.
Because this happens before the browser tells the server what
resource it wants, this part of the conversation can be based only on
the IP address on which the client connected. By the time the server
receives the Host
header field, it is too
late—the certificate has already been sent.
It is possible to run SSL hosts on ports other than port 443, if the port number is explicitly specified in the URL. This would allow you to get around this limitation, but it would put an additional burden on the end user to type the correct URL with the port number.
See Also
4.9. Logging for Each Virtual Host
Solution
Specify Errorlog
and CustomLog
within each virtual host declaration:
<VirtualHost *> ServerName waldo.example.com DocumentRoot /home/waldo/www/htdocs ErrorLog /home/waldo/www/logs/error_log CustomLog /home/waldo/www/logs/access_log combined </VirtualHost>
Discussion
The various logging directives can be placed either in the main body of your configuration file or within a <VirtualHost> section. When it is placed within a virtual host, log entries for that virtual host go in the specified logfile, rather than into the log file(s) defined in the main server configuration.
Warning
Each logfile counts against the total number of files and network connections your server is allowed to have. If you have 100 virtual hosts, each with its own error and activity log, that’s 200 open channels—and if the server’s quota is 256, you can only handle 56 concurrent requests at any one time.
In the recipe given here, the logfiles are placed within the home directory of a particular user, rather than in the main log directory. This gives you easier access to those files, but you still need to take adequate precautions to set the permissions on the directory in question. Consult Chapter 6 for a discussion on file permissions.
4.10. Splitting Up a LogFile
Problem
Due to a large number of virtual hosts, you want to have a single logfile and split it up afterwards.
Solution
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost CustomLog logs/vhost_log vhost
Then, after rotating your logfile:
split-logfile < logs/vhost_log
Discussion
The LogFormat
directive in this recipe creates a
logfile that is similar to the common
log file
format but additionally contains the name of the virtual host being
accessed. The
split-logfile
utility splits up this logfile into its
constituent virtual hosts.
See Also
4.11. Port-Based Virtual Hosts
Solution
Explicitly list the port number in the <VirtualHost> declaration:
Listen 8080 <VirtualHost 10.0.1.2:8080> DocumentRoot /www/vhosts/port8080 </VirtualHost> Listen 9090 <VirtualHost 10.0.1.2:9090> DocumentRoot /www/vhosts/port9090 <VirtualHost>
Discussion
Port-based virtual hosting is somewhat less common than other techniques shown in this chapter. However, there are a variety of situations in which it can be useful. If you have only one IP address, have no ability to add hostnames to DNS, or if your ISP blocks in-bound traffic on port 80, it may be useful to run virtual hosts on other ports.
Visitors to your web site must list the port number in the URL that they use. For example, to load content from the second virtual host previously listed, the following URL might be used:
http://server.example.com:9090/
See Also
4.12. Displaying the Same Content on Several Addresses
Problem
You want to have the same content displayed on two of your addresses.
Solution
Specify both addresses in the <VirtualHost> directive:
NameVirtualHost 192.168.1.1 NameVirtualHost 172.20.30.40 <VirtualHost 192.168.1.1 172.20.30.40> DocumentRoot /www/vhosts/server ServerName server.example.com ServerAlias server </VirtualHost>
Discussion
This setup is most useful on a machine that has addresses that are
internal to your network, as well as those that are accessible only
from outside your network. If these are the only addresses, you could
use the *
notation introduced in Recipe 4.1. However, if there are more addresses, this
allows you to specify what content appears on what address.
See Also
Get Apache Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.