The Apache web server has the ability to serve multiple websites from the same IP address, using virtual hosts. Each Virtual Host can be configured in the main server configuration file, or, thanks to the
Include or the
directives, in its own dedicated one. When the number of virtual hosts increases, their management starts to become troublesome. If their configuration is quite similar, we can manage them dynamically, thanks to the
mod_vhost_alias module. In this tutorial we will see how to do it.
In this tutorial you will learn:
- What is an Apache virtual host
- How to check if the mod_vhost_alias module is enabled
- How to load the mod_vhost_alias module on Debian and Red Hat family of distributions
- How to manage dynamic virtual hosts using the mod_vhost_alias module
Software requirements and conventions used
|Category||Requirements, Conventions or Software Version Used|
|Software||Apache web server|
|Conventions||# – requires given linux-commands to be executed with root privileges either directly as a root user or by use of
$ – requires given linux-commands to be executed as a regular non-privileged user
A quick virtual host overview
As we already mentioned in the introduction, the Apache web server has the capability to serve multiple websites using virtual hosts and the proper DNS configuration. The one below is a minimal yet typical virtual host definition:
<VirtualHost *:80> ServerName www.test.lan ServerAlias test.lan DocumentRoot /var/www/www.test.lan </VirtualHost>
This configuration will manage user requests to the
www.test.lan address, which is the value we set with the
ServerName directive, but also to
test.lan, which is the
ServerAlias. With the
DocumentRoot directive we set the base directory from which the files associated to the virtual host should be served, which in this case is
A virtual host can be defined in the main server configuration file (
/etc/httpd/conf/httpd.conf on the Red Hat family of distributions,
/etc/apache2/apache2.conf on Debian systems and its derivatives), or can be written in its own file and included from the main configuration. Indeed, if we take a look at the Apache configuration on the main Linux distributions, we can see that virtual hosts files are included via the
IncludeOptional directive from some specific directory.
On Fedora and related distributions, for example, we found the following configuration at the end of the file:
# Load config files in the "/etc/httpd/conf.d" directory, if any. IncludeOptional conf.d/*.conf
On Debian, instead:
# Include the virtual host configurations: IncludeOptional sites-enabled/*.conf
We can notice that the path from which the files should be included, is relative to the server root. The
IncludeOptional directive is used to include the virtual host files which should be named with the
.conf suffix. Here the
Include directive could also be used; what is the difference between the two? Both work exactly in the same way, the
IncludeOptional directive, however, does not cause an error when wildcards are used (as in this case) and no match is found, or if a path does not exist, in general.
For this setup to work, a proper DNS entry should also be configured. If working locally, however, we could simply add a line in the
/etc/hosts file. For example:
When virtual hosts configurations starts to increase, their management could easily become troublesome. A possible solution to this problem is to use dynamically generated virtual hosts. Let’s see how to do it with the mod_vhost_alias module.
Loading the mod_vhost_alias module
The first thing we have to do is to check if the mod_vhost_alias module is enabled. The command we want to run for this purpose depends on the distribution we are using. On Fedora and other distribution of the Red Hat family, we can use the following:
$ httpd -M | grep -i vhost_alias
On Debian, instead:
$ apachectl -M | grep -i vhost_alias
By passing the
-M option to the
apachectl) command, we obtain a list of loaded static and shared modules; piping the output to grep we can check if the module we need is in it. In case the module is not loaded, on Debian and its derivatives we can run the following command:
$ sudo a2enmod vhost_alias && sudo systemctl restart apache2
a2enmod command does create a symbolic link to the
/etc/apache2/mods-available/mod_vhost_alias.so file in to the
/etc/apache2/mods-enabled directory (similarly to what the
a2ensite command does for virtual hosts configurations), which is where modules are loaded from.
On the Red Hat family of distribution the list of loaded base modules is in the
/etc/httpd/conf.modules.d/00-base.conf file. Each module is loaded with the
LoadModule directive. If for some reason the
vhost_alias module line (67) is commented, just remove the comment, save the modification, and reload the httpd service:
$ sudo systemctl restart httpd
Once the module is enabled, we can proceed with the actual configuration.
Creating dynamic virtual hosts
The setup we are creating is based on the fact that the mod_vhost_alias module stores the dot-separated components of the requested virtual host name inside some variables we can reference and interpolate in the string we use to define the virtual host document root. If we take the
www.test.lan virtual host as an example, we will have:
- %0: The entire virtual host name
- %1: “www”
- %2: “test”
- %3: “lan”
Negative numbers could also be used, so, for example, we will have:
- %-1 The last part of the name, in this case “lan”
- %-2 The penultimate part, in this case “test”
It’s even possible to specify every component of the virtual host name from a certain port onward or backward. For example,
%2+ means “from the second part onward” and
%-2+ ‘causes the penultimate component and all the components that precede it to be included.
Supposing we want to use the
/var/www/ directory as the base of all our virtual hosts, we could create the following configuration in a file, let’s call it
<VirtualHost *:80> UseCanonicalName Off VirtualDocumentRoot "/var/www/%-2" </VirtualHost>
Let’s explain the configuration above. First of all we used the
UseCanonicalName directive and set it to “off”: we did this to be sure that the server name is taken from the “Host:” header in the HTTP request. We than used the
VirtualDocumentRoot directive. This directive is needed to set a dynamic path for the document root of a virtual host, by the use of the variables we saw above which are evaluated when managing a request.
www.test.lan virtual host is requested, automatically the files to be served for it will be searched inside the
/var/www/test directory. The use of the
%-2 negative index has the advantage that the setup will work both with
www.test.lan and for
test.lan, since it works backwards.
This is obviously just an example of what can be accomplished using the mod_vhost_alias module, and you can create the configuration which suits you better.
This kind of setup is quite practical if all the virtual host we are managing are pretty similar and require the same setup, but has its disadvantages, which can be pretty relevant depending on the situation. First of all, it will not be possible to specify virtualhost-specific settings, if not with the use of .htaccess files); this kind of setup will also cause problems if used together with standard virtual host configurations. Finally, the requests for all virtual hosts will be logged in the same file.
The Apache web server is able to serve multiple websites and resources from a single machine thanks to the use of virtual hosts. When the number of virtual hosts starts to increase in number it can become hard to manage them if each has its own configuration file/section. If they have similar settings we can workaround this problem using dynamically generated virtual hosts, taking advantage of the mod_vhost_alias module.
In this article we saw how to check if this module is enabled and how to enable it in the Debian and Red Hat families of distributions. We also saw how the components of the virtual host name are stored in variables, and how to use them to create dynamic virtual hosts. Finally, we saw what are the disadvantages of using this setup.