Debian

Simplifying repetitive Apache configuration with mod_macro

Apache is one of the more flexible webservers, and most of this is achieved via the use of various extension modules bundled with it, or externally available. mod_macro is a great module allowing you to simplifying configuration of multiple virtual hosts enormously.

Some of the available Apache modules, such as as mod_rewrite, are well-known, but others seem to be little-loved. In my opinion mod_macro is one module that should be much more popular than it seems to be!

The goal of mod_macro is two-fold:

  • To allow you to define macros.
  • To allow you to expand previously defined macros.

Why might you do this? Just to cut down on configuration inside your virtual hosts. This is particularly useful if you've started using the Let's Encrypt SSL provider, for example, but even without that if you have many virtual host definitions that contain repetition it is worth taking a look at it.

Imagine you have a webserver hosting multiple sites, you probably have a bunch of files beneath /etc/apache2/sites-enabled/, each one looking like this:

 <VirtualHost 1.2.3.4:443>    ServerName www.example.com    SSLEngine On   SSLProtocol all -SSLv2 -SSLv3   SSLHonorCipherOrder On   SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"    SSLCertificateFile    /etc/apache2/ssl/example.com.crt   SSLCertificateKeyFile /etc/apache2/ssl/example.com.key   SSLCertificateChainFile  /etc/apache2/ssl/le/bundle.pem    Redirect / https://example.com/ </VirtualHost>  <VirtualHost 1.2.3.4:443>   ServerName example.com    SSLEngine On   SSLProtocol all -SSLv2 -SSLv3   SSLHonorCipherOrder On   SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"    SSLCertificateFile    /etc/apache2/ssl/example.com.crt   SSLCertificateKeyFile /etc/apache2/ssl/example.com.key   SSLCertificateChainFile  /etc/apache2/ssl/le/bundle.pem    DocumentRoot /srv/example.com/public/htdocs </VirtualHost>  

Wouldn't it be simpler if you could replace those big blocks of SSL configuration with just a single line? After all the only thing that would vary across sites is the path to the certificate file(s).

mod_macro allows you to do that exact thing, and can be used pretty simply, we just need to enable the module, then define the macros we're going to use. To enable the module run:

 # a2enmod macro 

Then define our macros in a suitable configuration-file:

  • For Apache 2.2.x – on wheezy:
    • /etc/apache2/conf.d/macro.conf
  • For Apache 2.4.x – on jessie:
    • /etc/apache2/conf.enabled/macro.conf

Here's a simple definition of an SSL-macro:

  <Macro SSL $file>     SSLEngine On     SSLProtocol all -SSLv2 -SSLv3     SSLHonorCipherOrder On     SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"     SSLCertificateFile    /etc/apache2/ssl/$file.crt     SSLCertificateKeyFile /etc/apache2/ssl/$file.key     SSLCertificateChainFile  /etc/apache2/ssl/le/bundle.pem </Macro> 

Notice how the macro definition has the argument "$file" used in the definition, and then inline in the body? That's how you pass "variables" to your macro.

With this defined we can now simplify our previous configuration file to read:

 <VirtualHost 1.2.3.4:443>   ServerName www.example.com   use SSL example.com   Redirect / https://example.com/ </VirtualHost3>  <VirtualHost 1.2.3.4:443>   ServerName example.com   use SSL example.com   DocumentRoot /srv/example.com/public/htdocs </VirtualHost3> 

My personal Apache deployment tends to have a bunch of virtual hosts which just proxy to servers running on localhost, for that I've defined the following macro:

 <Macro Proxy $port>     <Proxy *>         Order allow,deny         Allow from all     </Proxy>     ProxyPass        / https://localhost:$port/     ProxyPassReverse / https://localhost:$port/     <Location />         Order allow,deny         Allow from all     </Location>     ProxyPreserveHost on     ProxyBadHeader ignore </Macro> 

Now I can define some hosts using it like so:

 # All traffic goes to 127.0.0.1:2013 <VirtualHost 80.68.84.111:80 [2001:41c8:10b:103::111]:80>    ServerName blog.steve.org.uk    Use Proxy 2013 </VirtualHost>  # All traffic goes to 127.0.0.1:2004 <VirtualHost 80.68.84.111:80>    ServerName ipv4.steve.org.uk    Use Proxy 2004 </VirtualHost> 

This setup is very simple to understand, use, and cuts down enormously on configuration.

For further details on using the module please do consult the Apache documentation.

Original Post

Leave a Reply

Your email address will not be published. Required fields are marked *