Pow is a zero-config Rack server for Mac OS X. Here I steal its idea to build a zero-config system based on Nginx with Passenger.

Auto Virtual Hosts

Since 0.8.25, Nginx supports named captures in server_name directive.

server {
  server_name   ~^(www\.)?(?<domain>.+)$;
  root  /sites/$domain;
}

It can be used to setup passenger virtual hosts and locate the rails/rack root directory based on the server name.

server {
  server_name ~^(.*\.)?(?<app>[^.]+)\.dev$;
  root /opt/apps/$app/public;
  rails_env development;
  passenger_enabled on;
}

The configuration above matches all sever names that ends with “.dev”, and use the 2nd level domain name to locate application root directory. For example, myapp.dev and www.myapp.dev both use the root /opt/apps/myapp/public, thus will serve the rails/rack app /opt/apps/myapp/.

Sure, /opt/apps can be changed to any directory accessible by Nginx. And remember to reload Nginx (nginx -s reload) after change the config file.

Now new app can be added just like Pow, creating a symbol link in /opt/apps.

cd /opt/apps
ln -s /path/to/myapp

We can setup more server blocks for different environments, for example:

server {
  server_name ~^(.*\.)?(?<app>[^.]+)\.staging;
  root /opt/apps/$app/public;
  rails_env staging;
  passenger_enabled on;
}

Add a record in /etc/hosts and open browser to see whether http://myapp.dev works.

127.0.0.1 myapp.dev

Local DNS Resolver

Pow starts its own DNS and utilizes Mac /etc/resolver system to resolve all subdomains of specified top-level domain to 127.0.0.1.

It is written for nodejs, and I wrote a simple wrapper simpledns to only start the DNS server in Pow.

  • Install nodejs first

  • Clone simpledns

    git clone git://github.com/doitian/simpledns.git
    
  • Read README.md in it and start the DNS server.

The server echoes something like

Save following content as files: /etc/resolver/dev

# File generated by simpledns/server.js
namespace: 127.0.0.1
port: 20560
# File content ends here

Follow the instruction and create the file in /etc/resolver.

Now remove the line 127.0.0.1 myapp.dev, restart your browser to see whether http://myapp.dev still works.