Apache configuration with mod_macro
April 29, 2008
After my brief brush with Lighttpd, I found that it couldn’t handle group authentication. So, instead, I decided to rewrite my Apache configuration, using mod_macro to obtain a more compact configuration. In the process, I discovered that I actually wanted that from the start, and only went to Lighttpd because it appeared to offer a simpler way to that. After a little poking around with it, its templating capabilities turned out to be quite weak compared to that of a properly equipped Apache.
The short version: My configuration is now 50% smaller, even with the addition of an extra virtual host or two. mod_macro is really kinda cool.
If you don’t know, mod_macro is an Apache module that lets you define macros. Astounding and surprising, isn’t it? In web programming, you’d be more correct in calling them templates: a named chunk of configuration directives, in which you can perform limited variable expansion. As a simple example, here is a macro that restricts access to a path:
<Macro RestrictAccess $url $userfile $username>
<Location $url>
AuthType basic
AuthName "Restricted access"
AuthUserFile $userfile
Require user $username
</Location>
</Macro>
You then invoke this macro and pass it parameters to inject into the template:
Use RestrictAccess /private /srv/www/.htpasswd dave
Using this mechanism, you can dramatically reduce the size of your apache configuration, especially with several virtual hosts with redundant statements. I used macros to do just that. Let’s construct a set of macros to aid us in configuring virtual hosts.
First of all, let’s standardize and fold away all the tedious boilerplate of virtual hosts: defining the server name, the logging configuration, and default access directives.
<Macro DocrootLoggingAccess $name $vhost_dir>
ServerName $name
ServerAdmin dave+httpd_$name@...
DocumentRoot ${APACHE_WWWROOT}/$vhost_dir
CustomLog ${APACHE_LOGROOT}/$vhost_dir/access.log combined
ErrorLog ${APACHE_LOGROOT}/$vhost_dir/error.log
LogLevel warn
ServerSignature off
<Directory ${APACHE_WWWROOT}/$vhost_dir>
AllowOverride None
Order allow,deny
Allow from all
</Directory>
</Macro>
Note the use of APACHE_WWWROOT and APACHE_LOGROOT variables. These are environment variables, which Debian’s apache package helpfully lets us define in /etc/apache2/envvars. Debian uses this mechanism to define things like the PID file path, which gets pushed into the configuration, but also gets included by debian helper scripts, like the start-stop daemon. I subverted the mechanism to define my own global configuration variables:
export APACHE_WWWROOT=/srv/www
export APACHE_LOGROOT=/srv/logs/www
This lets me define paths relative to these global roots, which makes the configuration look much nicer. With this macro alone, a virtual host for serving static files becomes as simple as:
<VirtualHost *:80>
Use DocrootLoggingAccess static.natulte.net natulte.net/static
</VirtualHost>
That will serve the content of /srv/www/natulte.net/static on http://static.natulte.net . Don’t try it, it was just an example, I’m not actually serving anything there :-)
I won’t go over the other macros I have in detail, but here is a quick overview:
# Configure a FastCGI dynamic instance to handle all .php files through PHP 5
Use PHP5
# Serve the Trac environment 'nxos' under URL path /nxos, via FastCGI.
# Logins to the environment should use authentication data for
# domain natulte.net, group 'nxos-dev'
#
# This macro makes use of an APACHE_TRACROOT envvar.
Use Trac nxos /nxos natulte.net nxos-dev
# Serve a read-only copy of the nxos mercurial repositories under /hg
#
# Uses the APACHE_HGROOT envvar.
Use MercurialReadOnly nxos /hg
# Same as above, but authenticate write access using natulte.net's
# authentication data (access to specific repositories is configured in
# each repo directly, apache needs only to identify potentially acceptable
# users).
Use Mercurial nxos /authenticated-hg natulte.net
# Configure the given URL path as a Dokuwiki instance (directory access and
# rewrite rules).
Use Dokuwiki /wiki
# Activate /server-status and /server-info on this vhost. Useful for
# debugging broken macro expansions.
Use ServerStatus
Use ServerInfo
# Small helper template: given a domain name, include configuration directives
# for HTTP Basic authentication using user/group data global to that domain.
# Reused in all the above templates that do authentication.
Use AuthData natulte.net
I won’t bore you with any more gruelling details. Suffice it to say that, with this set of macros, the configuration for, say, nxt.natulte.net goes from a 50 line monstrosity of boilerplate and weird FastCGI directives, to:
# Notice how I can still add snippets of configuration. I just
# don't have boilerplate rubbish any more!
<VirtualHost *:80>
Use DocrootLoggingAccess nxt.natulte.net natulte.net/nxt
Use TracEnv nxos /nxos/trac natulte.net nxos
Use MercurialReadOnly nxos /nxos/hg
<Location /nxos/docs>
Options Indexes
</Location>
</VirtualHost>
Thanks to mod_macro, I’m happy with my web server configuration for the first time in a while. It’s as code should be: compact, common elements refactored, no duplication, and above all, clear and easy to understand.