dscl - the easy way to add hosts on OS X

As a web developer, I often want several host names pointing at my local machine whilst developing and testing applications. I may want to use Apache virtual hosts to serve multiple apps at once, or use subdomains to distinguish different accounts within a single application.

Previously, to set these host names up, I would manually edit /etc/hosts, adding entries like:

127.0.0.1      twitter-killer.localhost
127.0.0.1      my-url-shortener-is-better-than-yours.localhost
127.0.0.1      yet-another-half-baked-idea.localhost

This worked well on one level, but on another it just seemed wrong. It’s very manual, prone to error and pretty hard to script. Recently though, thanks to a hint from Chris Parsons, I’ve found another way: using dscl.

dscl, or Directory Service command line utility to give it its full name, has many uses. For a web developer, the most relevant is probably the ability to add, list and create local directory entries under /Local/Defaults/Hosts in the directory (not the file system). These act like lines in /etc/hosts but can be manipulated easily from the command line.

To add an entry (easily the most interesting command) use:

sudo dscl localhost -create /Local/Default/Hosts/twitter-killer.localhost IPAddress 127.0.0.1

Once entries have been added, listing them is just as simple:

sudo dscl localhost -list /Local/Default/Hosts IPAddress

This produces a list in the form:

twitter-killer.localhost                         127.0.0.1
my-url-shortener-is-better-than-yours.localhost  127.0.0.1
yet-another-half-baked-idea.localhost            127.0.0.1

Finally, you can remove entries with:

sudo dscl localhost -delete /Local/Default/Hosts/twitter-killer.localhost

Once you’ve mastered these commands, the possibilities are endless. Here’s a rake task to add all subdomains used in a project:

class Application
  def self.subdomains
    Client.all.collect {|client| client.subdomain }
  end
end

namespace :subdomains do
  task :add do
    Application.subdomains.each do |subdomain|
      `sudo dscl localhost -create /Local/Default/Hosts/#{subdomain}.app.localhost IPAddress 127.0.0.1`
    end
  end

  task :remove do
    Application.subdomains.each do |subdomain|
      `sudo dscl localhost -delete /Local/Default/Hosts/#{subdomain}.app.localhost`
    end
  end
end

Or if you’re using passenger for development, you can use a tool like James Adam’s hostess to automatically set up the host entry and virtual host entry for a site in one simple command.