Mike Rockétt

Macroify your Apache Virtual Hosts

If you’re on Windows, chances are you don’t have a handy package like Valet to make your development-workflow easier. If you’re using a standard Apache installation, this might go a long way in speeding things up.

#Apache — 20 December 2020

Jan 2020 Update: I’ve since moved on to the world of MacOS, and I use Valet (as of 2017 – 18). If you develop on Windows, I’m keeping this here in case it’s of any help.

Ever since I started developing for the web and discovered Apache, it was tedious for me to have to create a new virtual host every time I wanted to work on a new site – as if editing the hosts file was bad enough.

At the onset, I searched for a way to make a wildcard virtual host that would shorten the process of starting up a new development domain considerably. Since then, I’ve been through several iterations of this, and would like to share my current setup with you.

Config file

For starters, I’m not using the default httpd-vhosts.conf file – for some reason, I wanted my virtual hosts to be called ‘virtuals’, and so I created a new config file for that, and included it in httpd.conf:

Include conf/virtuals.conf

Before I begin with the code, here’s the virtual host tree I’m working with now:

- domain
- public_html (document root, maps to domain.local)
- subdomain
- public_html (subdomain document root, maps to subdomain.domain.local)

domain and subdomain are ​‘site-roots’, which are handy for apps that need to access one level above the document root.

To begin, we need to define two macros in the virtuals.conf file.

Directory macro

The first macro defines the structure of our directory configuration:

<Macro Directory $dir>
<Directory "z:/var/www/$dir/public_html">
Require all granted
Options Includes Indexes FollowSymLinks
AllowOverride All

This is the simplest directory config you’d need, and covers most situations – it’s obviously easy enough to override. Note how $dir is pulled into the path from the macro parameter (just after the name definition).

Subdomain macro

Now, the next macro is for subdomains. Unfortunately, this is required as the wildcard approach doesn’t seem to work for me, keeping in mind that I prefer subdomain document roots to be located in the main domain’s directory (one up from its document root).

<Macro LocalSub $sub $domain>
ServerName $sub.$domain.local
DocumentRoot "z:/var/www/$domain/$sub/public_html"
Use Directory $domain/$sub

This macro is called LocalSub, and pulls in two variables: one for the main domain, and the other for the subdomain. This is provided to ServerName and DocumentRoot. And lastly, this virtual uses the Directory macro we defined above.

Much like the Use directive above, we’ll need this for declaring subdomains on an individual basis as well. Unfortunately, this means an Apache-restart is required.

To create a virtual for a subdomain, simply call the Use directive:

Use LocalSub blog rockettpw

Here, blog is the subdomain, and rockettpw is the main domain, resulting in blog.rockettpw.local.

The main virtual host

Now that’s out of the way, we can proceed to create the main virtual host, which captures *.local (this should go underneath your subdomain imports):

UseCanonicalName Off
ServerAlias *.local
VirtualDocumentRoot "z:/var/www/%-2/public_html"
Use Directory *

If you’re not sure what %-2 is, it’s simply telling Apache to pull the * from the server alias (we need to use an alias and not a name due to the wildcard – also note that we do not need UseCanonicalName for the same reason). Specifically, it means the second last portion of the alias, where each portion is separated by a period (.).

Lastly, we import the directory config, using the macro once again. This time, however, we declare a wildcard for the directory, which would result in z:/var/www/*/public_html. This does not apply the configuration to all th directories – it is specific to the virtual being requested.


As you can see, the process is quite straight-forward. Once you’ve set this up, all you need to do is add a directory and document root for a new site, and don’t forget to add the entry to the hosts file.

You could, as an alternative, use Acrylic, which allows you to use wild-card hosts, like *.local. I’m unable to get it working on my end, but it’s more than likely due to my network adapter configuration (unable to diagnose).