Quick guide to wildcard Apache vhosts

[Edit: Added wildcard DNS section at the end, also link to dnsmasq setup instructions; also quick info on nginx defaults]

After my Debugging Drupal talk at Copenhagen today a lot of people wanted to know how to use a wildcard virtualhost, so I promised a quick writeup.

The purpose here is to be able to deploy new virtualhost-style Drupal sites on your localhost without doing any apache configuration (or /etc/hosts, if you deploy a nameserver).

Most of the time Drupal works better (and more like your production site) if you run it as a production site. If I have a site like debugging_example.com, I run it locally as debugging_example.l. That's way better than localhost/debugging_example, because all the URLs work right, and it's clean URLs.

The basic idea of what you have to do:

  • Enable mod_vhost_alias in Apache
  • Configure a catchall virtualhost
  • Tweak your .htaccess by uncommenting one line
  • Make an entry in your /etc/hosts

Here's the quick version of how to do it:

  1. Enable the mod_vhost_alias Apache module with sudo a2enmod vhost_alias (on Debian/Ubuntu, or however on your environment).
  2. /etc/init.d/apache2 restart
  3. Configure your httpd.conf or apache2.conf or whatever to provide a catchall. I use Debian/Ubuntu, and this is done with:
    • Create the file /etc/apache2/sites-available/catchall. Here is my catchall. You'll note you have to change the base path.
    • a2ensite catchall
    • /etc/init.d/apache2/reload
  4. Make an entry in your hosts file for the virtualhost you want to use.
  5. In your drupal .htaccess, uncomment the line that says
    # RewriteBase /
    so it says instead:
    RewriteBase /

And if you are ambitious and don't like adding each entry to /etc/hosts, here's a crude recipe for running bind9 (debian/ubuntu) to automatically resolve anything. I use *.l:

  • /etc/bind/named.conf.local, add
    zone "l" {
            type master;
            file "/etc/bind/db.l";
            notify no;
    };
  • Add the file /etc/bind/db.l, adjusted for your use:
    $ttl 38400
    @ IN SOA l.l. admin.l. (
    2009091700
    10800
    3600
    604800
    38400 )
    l. IN NS localhost.
    *.l. IN CNAME localhost
  • Change your computer to use localhost to resolve names. You can do this in the network config applet.

Update 2011-05-03: You might be interested in this article which shows how to do the same thing using dnsmasq, a lighter-weight DNS server.

Update 2011-05-03: To do the same thing in nginx as we did with Apache, this rule in /etc/nginx/sites-available/default will make nginx recognize any hostname like xxx.l or xxx.b or xxx.bigsony or www.xxx.b and send it to the /home/rfay/workspace/xxx directory.

  server_name   ~^(www.)?(?<domain>.+).(l|bigsony|b)$;
  root /home/rfay/workspace/$domain;

17 comments

by Visitor on Wed, 2010-08-25 01:19

Could you clarify why we need to uncomment in .htaccess about RewriteBase, what's the reason behind this step?
Thank you very much,
Francesco

by rfay on Wed, 2010-08-25 01:22

Hi Francesco - Unfortunately you just can't use the VirtualDocumentRoot without doing that. Clean URLs don't work.

by Francesco on Wed, 2010-08-25 01:27

I see, that's probably something that can be put at configuration level so you don't need everytime in .htaccess.
Is it possible to put the RewriteEngine On + RewriteBase / in the VirtualHost configuration?
Thanks for the quick reply!
Francesco

by rfay on Wed, 2010-08-25 05:27

I think it would work. Try it and report back. Thanks!

by Aaron on Wed, 2010-10-27 15:34

This is a fantastic guide, Randy.

Francesco: have you managed to get the directives to work in the Virtual Host configuration? I've played with your suggestion and others but it appears maybe RewriteBase cannot be specified in the vhost?

by Scott on Mon, 2011-02-07 09:30

RewriteBase: only valid in per-directory config files

So it's only valid in the .htaccess files.

by Bevan on Wed, 2010-08-25 18:04

I'm glad to see my first patch to Drupal core — as trivial as it was — has been useful! :)

http://drupal.org/node/118569

by drifter on Wed, 2010-08-25 01:52

/etc/hosts doesn't support wildcard entries, but DNS entries do.

A bit more complicated, but you could enable a DNS server like BIND. Basically, set up DNS forwarding to your ISP's nameservers, or something like Google DNS or OpenDNS:

forwarders {
      8.8.8.8; // google
      8.8.4.4;
};

Create your own zonefile, setting in named.conf:

zone "mac" IN {
        type master;
        file "mac.zone";
        allow-update { none; };
};

And the zonefile:

$TTL  86400
$ORIGIN mac.
@            1D IN SOA   @ root (
                   42      ; serial (d. adams)
                    3H      ; refresh
                  15M     ; retry
                    1W      ; expiry
                   1D )        ; minimum

         1D IN NS    @
          1D IN A     10.37.129.2
*       IN      A       10.37.129.2

I used 10.37.129.2, that's my virtual adapter connecting with Parallels Desktop, so I can reach the domains from Windows virtual machines too. You can use 127.0.0.1 instead.

From then on, just create a directory, modify .htaccess, and it should work, any domain ending in .mac: a.mac, b.mac etc...

by rfay on Wed, 2010-08-25 05:28

I added the config I use into the article. Thanks for posting this.

by mavimo on Wed, 2010-08-25 06:19

I prefer dnsmasq, a really, really, REALLY simple DNS manager.

sudo apt-get dnsmasq
sudo nano /etc/dnsmasq.conf
# add
#   address=/l/127.0.0.1
# on end and save
sudo /etc/init.d/dnsmaq restart
sudo nano /etc/resolv.conf
# add (on top)
#   nameserver 127.0.0.1
# and save

that's all :)

by Chris Cohen on Wed, 2010-08-25 08:43

When you say...

Enable the mod_vhost_alias Apache module with sudo a2ensite mod_vhost_alias

Should this be a2enmod rather than a2ensite?

by rfay on Wed, 2010-08-25 08:59

Sorry - fixed it. Of course it should be a2enmod. a2ensite is in my fingers.

by Sean on Wed, 2010-08-25 14:14

Great info on a tough topic, thanks Randy!

by Henrik Sjökvist on Mon, 2010-08-30 08:13

I use http://github.com/bjeanes/ghost to add DNS entries as needed.

To install (assuming you have ruby and RubyGems installed):

gem install ghost

To add a new entry pointing to 127.0.0.1 just enter something like:

sudo ghost add mysite.local

by CSÉCSY László on Sun, 2010-10-24 09:32

I have translated it to Hungarian (available here), and packed some more techniques into the post, based on the comments.

by marco on Tue, 2011-09-06 07:50

FYI: the catchall file is gone :)

by rfay on Tue, 2011-09-06 07:54

Thanks for letting me know. I updated the pointer and it's here: http://randyfay.com/sites/default/files/catchall

Drupal theme by Kiwi Themes.