Enabling Dynamically Configured Name-based Virtual Hosting on Mac OS X

Enabling virtual hosting on your Mac OS X machine will allow you to serve web content from a single IP address for multiple domain names, including sub-domains. This is useful for having a local development environment on your laptop, as you never need to edit your web server config files, just create additional folders matching the site names you want to work with.

Note: the original version of this document was created for pre-Leopard Mac OS X versions. See the previous revision here. This version references Apache 2.2 on Mac OS X Leopard, and recommends editing the hosts file rather than using NetInfo.

All the following involves editing Apache server config files, which requires admin privileges. They are located at /etc/apache2/httpd.conf (main config file) and /etc/apache2/extras/httpd-vhosts.conf (file that is included, keep all your virtual host related config here), and it's best to make a backup before you begin (just copy the original with a new extension like "bak", e.g. /etc/apache2/httpd.conf.bak).

First, you need to uncomment the sections related to virtual host aliasing in your main httpd.conf file, by deleting the # in front of the following lines:

#LoadModule vhost_alias_module libexec/httpd/mod_vhost_alias.so
#AddModule mod_vhost_alias.c

You'll also need to uncomment the include which will pull in the next file, again by removing the # from in front of Include.

# Virtual hosts
#Include /private/etc/apache2/extra/httpd-vhosts.conf

Decide where you want to put all your web files. I placed them all in a directory next to the main, default server, at /Library/WebServer/Hosts. Create that directory.

Now add this snippet at the end of the /etc/apache2/extras/httpd-vhosts.conf file:

#allow access to the Hosts directory where your sites are
<Directory "/Library/WebServer/Hosts">
Options Indexes FollowSymLinks MultiViews
AllowOverride All
#you could configure the following to only allow access from localhost
Order allow,deny
Allow from all
</Directory>

#get the server name from the Host: header
UseCanonicalName Off
VirtualDocumentRoot /Library/WebServer/Hosts/%0/html

Now restart your web server with the command apachectl graceful If you don't see any errors, everything should be working.

At this point, you should be able to add folders like /Library/WebServer/Hosts/example.bmannconsulting.com/html and you're good to go. You can also use symlinks, so have multiple domains point to the same content. Remember, you either need to have DNS for the domain set up correctly or edit your hosts file at /etc/hosts. An example of that would be adding a line like 127.0.0.0.1    example.local to the end of the file -- it's corresponding web directory would then be /Library/WebServer/Hosts/example.local/html.

Note: For those developing Drupal multisite, any additional sites you want to develop on the same codebase, just symlink to your base Drupal install. So, if your base install is at base.example.local, and you want to create newsite.example.local, symlink /Library/WebServer/Hosts/newsite.example.local to /Library/WebServer/Hosts/base.example.local. You will still need to create the directory for the newsite at /Library/WebServer/Hosts/base.example.local/html/sites/newsite.example.local for Drupal to properly pick it up.

Related Links

Comments

Not quite working

I followed your instructions above and am having a problem. I have two registered domains: www.garrettwilkin.com www.mastermindsunlimited.net and I would like them to point to different directories on my one ip address. The host machine's rendezvous name is marley.local. After following your instructions I received 404 errors. So I cheked the error log, and the server was looking for files in: /Library/WebServer/Hosts/marley.local/Documents/ It always looks there no matter which domain I use, www.garrettwilkin.com & www.mastermindsunlimited.net both result in the server looking for files in: /Library/WebServer/Hosts/marley.local/Documents/ but I would expect www.garrettwilkin.com to result in /Library/WebServer/Hosts/www.garrettwilkin.com/Documents/ and would expect www.mastermindsunlimited.net to result in /Library/WebServer/Hosts/www.mastermindsunlimited.net/Documents/ What did I do wrong? PS - My server is behind a router with address 192.168.1.100, and the routing forwards ports 80 and others to the server only. garrett.wilkin@gmail.com

Worked with older versions of OS X

It seems there were changes to OS X and the Apache that shipped with it so that this no longer works. I haven't tested on Tiger yet (which I'm running now) and don't have it set up locally.

If someone were to track down the changes needed, I'd love to update this post.

Note: ScriptAlias overrides VirtualScriptAlias !

A quick note to help anybody else who has had this problem. I changed my httpd.conf as described above and found that the docs for the different domains worked fine but the cgi-bin did not. Apache kept giving me a 404 error. The error log said "script not found or unable to stat: /Library/WebServer/CGI-Executables/test.cgi". This shows that it was still looking at the old directory. I had to comment out the ScriptAlias line for VirtualScriptAlias to work (the one sitting alone and not in a VirtualHost block).

SSL Certificate

Would it possible to enable some of the virtual hosts for SSL access (i.e. http://www.somedomain.com)?

SSL needs a dedicated IP addr

SSL needs a dedicated IP address, if I'm not mistaken. You should be able to mix IP-based hosts with name based virtual hosts (as the solution above describes). The IP-based virtual hosts would need to be defined separately.

SSL Certificate #2

Oops .. I meant https://www.somedomain.com. Sorry :)

Hallelujah!

This must be the most valuable how-to a web developer using OS X could ever find. Like emd, I've been struggling with the block level directives. This is so much better; I never even knew this module existed. No, I would not change the title of your article because if it was called mass virtual hosting, I would have thought it was out of my 'scope.' But you might mention that this can be an simpler, more flexible alternative to the block level virtual host directives—just to avoid confusion.

1 thing I ran into while following your instructions, to restart Apache, it was necessary for me to sudo the command…
sudo apachectl graceful

That might trip some people up since Apache's feedback is somewhat ambigous here. Also, note that if you don't use the terminal to restart Apache(i.e. you try to Start/Stop it in the System Preferences Web Sharing panel) OS X will overwrite your httpd.conf file, unless you make sure to stop Web Sharing it before you make your edits.

A couple questions:

Is it possible to set up a default set of options for all new virtual hosts(e.g. Options +Indexes +Multiviews +FollowSymLinks)? Right now I'm putting them in an .htaccess file.

Does this in any way affect any existing VirtualHost blocks in the httpd.conf; can they coexist peacefully?

Awesome tutorial—thanks.

Glad you like it

Great comments. Yes, sudo is needed for many commands, including apachectl.

I will look into default options. I've just moved to a new machine where I will be setting this up from scratch again. It makes sense that you should be able to set default options. Hmmm...my guess is that you could set defaults by using a Directory block that applied to all the VirtualHosts. Another VirtualHost block and/or local .htaccess file could override these defaults.

I'm also not certain on the compatibility with existing VirtualHost blocks. I believe any VirtualHost directives will override settings for any particular host -- the mod_vhost_alias directives really only set the document root and script alias, not any other options.

Any new info will be appended to the existing document.

Weird

I have virtual hosts on my machine and I didn't have to uncomment those lines...it seems to work.

I used VirtualHost declarations.

I don't know if I should chan

I don't know if I should change the title or not. Technically, this is for "dynamically configured" virtual hosts -- that is, you don't actually have to define *any* hosts ahead of time. I think Apache actually calls this "mass virtual hosting".

Basically I can create a new "host" just by adding a directory that matches the name of the host -- no httpd.conf edits or Apache reloads required. This is what the mod_vhost_alias enables.