Devoured By Lions

the eternal struggle to tame complexity

Apache Configuration

One frustrating thing about Apache is how unamenable its configuration system is to parameterization, generalization, and reuse. To start with, even in the simplest Apache configuration one typically wants to parameterize the configuration file that Apache uses, and the stock apachectl has meagre support for parameterization (although it does source the envvars file; this mechanism is still hard to use to support multiple separate configurations). But beyond the wrapper script (which I think most people just copy, modify or rewrite entirely anyway), there is no consistent variable/parameter expansion support in the configuration system. Sure, specific modules and directives support some for of parameterization, but they are usually bespoke, awkward and incompatible with each other (the prime culprit being mod_rewrite which is its own adhoc language). Here is a short list of some of the inconsistent parameterization capabilities:

* “environment” variables
* Defines
* mod_rewrite RewriteRule and RewriteCond backreferences
* Parameter expansion in mod_vhost_alias

I am currently trying to design and implement an architecture that consists of a frontend Apache instance that proxies to backend user Apache instances (from my current mess which is single Apache instance where I tried in vain to apply various inconsistent parameterization approaches above to allow multiple users to share the same Apache instance; ultimately I decided true isolation is really the best and simpler approach). This is almost complete however my last stumbling block is how to compose the backend user Apache config from a large stock configuration plus a minimal (would be unnecessary if the main config could be properly parameterized!) user config that specifies User/Group and Listen port.

First I thought I could have the master config include every user config, but wrap each user config with a define that ensures only the proper config is used. E.g.:

httpd -f backend.conf -DUSER_FOO

master.conf: Include users/*.inc


<IfDefine USER_FOO>
...


This actually works, although I realized one drawback is that each user’s config must be readable by all other users. Apache will not start up if one of the includes is unreadable. This also renders the conditional configuration moot.

My second attempt was to have the main Apache config include a generic user config at a fixed location:

Include user.inc

A setup script ensures that the correct user config is linked in the location that their Apache instance will ultimately find. Read access to each user’s config can be restricted. However this requires a yet another manual (well, it’s automated, but it’s still superfluous) configuration step.

My last attempt was to use Apache’s -f flag to specify two configuration files on the command line.

httpd -f backend.conf -f user_foo.conf

This theoretically offers the benefit that each user’s Apache server root (each user must have their own ServerRoot because, yet again, Apache configuration is not parameterizable enough to use a shared root) can be identical. This superficially appears to work…however I discovered that it doesn’t really work because the two config files are not actually composed in the way I would expect (that is, both parsed under the same context such that the second and subsequent config files observe configuration set by preceding files). In reality what happens is that each file is parsed independently and instead of previously parsed configuration being observed, the built-in Apache defaults are used. That means, for example, if you set the DocumentRoot in one config file, but omit it in the next…it doesn’t actually get used. The omission in the second file causes the default to override the previously parsed value!

So ultimately I’m going to have to revert to strategy #2.

If the Apache config just supported a consistent parameter expansion syntax throughout (e.g. like a pre-processor, so that support doesn’t have to be manually implemented in every single directive) I suspect that most of the configuration could be boiled down to a single shared config file. (Yes I realize that pre-processor parameter expansion is not alone sufficient since things need to be parameterized at runtime as well; but that is not the type of parameterization needed for the above scheme). Other Apache products (Ant, Maven, Tomcat, etc.; all Java based…) seem to support this type of parameterization.

I remember seeing a Google Summer of Code proposal for redesigning the Apache config so maybe there is some hope (although I can no longer find any reference to it).