Monday, December 3, 2007

Templatize your Apache configuration with mod_macro

Background

In a previous post I presented a way to clean up your Apache's configuration by putting your sites' configuration apart from your httpd.conf. In this one I will show you how to build a scheme to easier the maintenance of your Apache related configuration by avoiding some nasty copy/paste.

Current situation

Current apache structure

Let's analyze the structure of the current /etc/apache2/ directory displayed in the picture on the right:

  • httpd.conf is the single entry point for Apache's configuration, it contains the bare minimum configuration needed for the server's instance.
  • modules.d is the directory containing all modules and features configuration files, it is Gentoo's equivalent to handle the mods-enabled directory of Debian and derivatives. Those files are included from the httpd.conf with:
    Include /etc/apache2/modules.d/*.conf
  • vhosts.d is the directory containing all virtual host configuration files as explained in my previous post. This one is the equivalent of sites-enabled. Those files are included the same way than modules.d with:
    Include /etc/apache2/vhosts.d/*.conf

Lets have the configuration of www.example.org, wiki.example.org and forum.example.org all hosted by the same Apache instance.

Content of vhosts.d/www.example.org:

<VirtualHost *:80>
    ServerName www.example.org
    DocumentRoot /var/www/www.example.org

    ErrorLog /var/log/apache2/www.example.org/error_log
    CustomLog /var/log/apache2/www.example.org/access_log common
    php_admin_value error_log "/var/log/apache2/www.example.org/php_error_log"
</VirtualHost>

Content of vhosts.d/wiki.example.org:

<VirtualHost *:80>
    ServerName wiki.example.org
    DocumentRoot /var/www/wiki.example.org

    ErrorLog /var/log/apache2/wiki.example.org/error_log
    CustomLog /var/log/apache2/wiki.example.org/access_log common
    php_admin_value error_log "/var/log/apache2/wiki.example.org/php_error_log"
</VirtualHost>

Content of vhosts.d/forum.example.org:

<VirtualHost *:80>
    ServerName forum.example.org
    DocumentRoot /var/www/forum.example.org

    ErrorLog /var/log/apache2/forum.example.org/error_log
    CustomLog /var/log/apache2/forum.example.org/access_log common
    php_admin_value error_log "/var/log/apache2/forum.example.org/php_error_log"
</VirtualHost>

We may notice that strong conventions are used:

  1. Document root is located in /var/www/$FullyQualifiedDomainName
  2. All logs are stored inside /var/log/apache2/$FullyQualifiedDomainName
  3. Only the $FullyQualifiedDomainName differs from one configuration to another.

mod_macro in action

Because the configuration of the virtual hosts follow all the same rules, this is a perfect candidate for Fabien COELHO's mod_macro. This Apache module lets you define and use macros within Apache runtime configuration files. Just take a look at the following macro:

# Macro definition for a generic virtual host
<Macro VHost $fqdn>
    <VirtualHost *:80>
        ServerName $fqdn
        DocumentRoot /var/www/$fqdn

        ErrorLog /var/log/apache2/$fqdn/error_log
        CustomLog /var/log/apache2/$fqdn/access_log common
        php_admin_value error_log "/var/log/apache2/$fqdn/php_error_log"
    </VirtualHost>
</Macro>

Here is how the content of my virtual hosts configuration:

Content of vhosts.d/www.example.org:

Use VHost www.example.org

Content of vhosts.d/wiki.example.org:

Use VHost wiki.example.org

Content of vhosts.d/forum.example.org:

Use VHost forum.example.org

While this solution is just perfect in case every virtual hosts should be configured exactly the same way (in that case you may be interested in mod_vhost_alias) it doesn't provide much flexibility to modify a specific virtual host afterwards even temporarily. To overcome to this shortcoming, here is my final structure:Updated Apache structure

  • an additional macros.d to holds macros definitions into .conf files loaded with:
    Include /etc/apache2/macros.d/*.conf
  • a home made VirtualHost definition made in two parts:
    # Macro definition for a generic virtual host
    <Macro BeginVHost $fqdn>
        <VirtualHost *:80>
            ServerName $fqdn
            DocumentRoot /var/www/$fqdn

            ErrorLog /var/log/apache2/$fqdn/error_log
            CustomLog /var/log/apache2/$fqdn/access_log common
            php_admin_value error_log "/var/log/apache2/$fqdn/php_error_log"
    </Macro>
    <Macro EndVHost>
        </VirtualHost>
    </Macro>
  • virtual hosts defined with:
    Use BeginVHost www.example.org
        # Define specific virtual host configuration here.
        # Example:
        # Use ZendFramework

    Use EndVHost

Conclusions

This post doesn't attempt to state the best way to manage tons of virtual host configuration, for each environment, there are different considerations to be taken and there's no perfect way. The main reason I wrote this post was to share the lessons learned with mod_macro and Gentoo's way to organize things and maybe helping others to improve their Apache configuration.

1 comment:

ntom-taylor said...

The mod_macro should be included with apache by default. why they dont have this and just let people bundle there httpd.conf with endless copy/pasting of basically the same info is beyond me. .

Good post and good tips.
Regards,
Tom Taylor