How to manage dynamic virtual hosts with Apache and the mod_vhost_alias module

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
apache-logo

Software requirements and conventions used

Software Requirements and Linux Command Line Conventions
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.



Comments and Discussions
Linux Forum