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 IncludeOptional
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 |
---|---|
System | Distribution independent |
Software | Apache web server |
Other | Root permissions |
Conventions | # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command$ – 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 /var/www/www.test.lan
.
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:
127.0.0.1 www.test.lan
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 httpd
(or 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
The 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 dynamic_vhost.conf
:
<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.
When the 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.
Disadvantages
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.
Conclusions
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.