Serve Ruby on Rails, PHP, and Node with Pow (POW!)


by Gerard Sychay

Note that Pow runs only on Mac OSX

Here at Differential, we work on diverse projects. Serving up Rails apps, PHP apps, and Node apps with zero configuration is the Holy Grail of development environments. Okay, I made that up, but it's pretty darn challenging. Well, this post will not tell you how to do these things with zero configuration, but it gets pretty darn close.

As a reminder, there are two requirements for serving up your awesome web app from your laptop.

  1. DNS – app.dev, project.local, dev.test or whatever domain and TLD you decide to use must resolve to 127.0.0.1.
  2. Application server – Once the request hits your machine on some port, some application server must route it to your application code.

Ruby on Rails

I won't go into much detail here as Pow has already figured this one out and is the de facto standard-bearer. So get Pow, install it, and use it to get a 1-step configuration for new projects. For the record (we'll need this later), that one step is:

$ ln -s /path/to/projects/railsapp ~/.pow/railsapp  

And http://railsapp.dev should load your Rails app.

PHP

While Pow serves up Rack apps with a custom server, our old friend Apache is still the easiest way to run PHP apps. We'll need to do a few things to get zero-configuration PHP apps running.

  1. Assuming all of our Rails apps have symlinks, we take advantage of Pow's proxying and default virtual host features to proxy any non-Rack app to port 81, where Apache will be listening.

    $ echo 81 > ~/.pow/default  
    

  2. Now of course we have to configure Apache to listen on port 81. On Mac, this is in the file /etc/apache2/httpd.conf under the Listen directive. Change this value and bounce Apache.

  3. We want Apache to serve any PHP folder without having to specify a virtual host each time. Apache has a nifty directive called VirtualDocumentRoot which allows host variables in your document roots. Create a VirtualHost block that looks something like this somewhere in your Apache config.

    <VirtualHost 127.0.0.1:81>  
       ServerName any.dev
       ServerAlias *.dev
       VirtualDocumentRoot "/path/to/projects/%1"
    </VirtualHost>  
    

Thanks to Pow proxying and VirtualDocumentRoot, simply creating a directory at /path/to/projects/phpapp should immediately be available at http://phpapp.dev

Node

Weighing in at two commands, node apps require the most amount of work. We simply proxy Pow requests to whatever port your node app is running on. So if you start your node app on port 3000, then create a proxy file for Pow to port 3000 for your app. Nothing fancy.

$ echo 3000 > ~/.pow/nodeapp  

Then cd to your node project directory, and start your app however it starts. For example,

$ node app.js

And your node app should be available at http://nodeapp.dev. I await a Pow for node.

UPDATE: Node instructions also apply to Meteor. However in the case of either node or Meteor, Websockets are not proxied, so they will usually fall back to Ajax polling.

Using .local as a TLD

If you prefer to use .local as your development TLD, as I do, then there is a potential problem on Mac as that is the TLD Mac uses for Bonjour. To avoid DNS lookup delays or failures, run a local DNS nameserver. Mac OS ships with such a nameserver in BIND. To enable and configure BIND, read Setting up wildcard DNS on localhost domains on OSX. There are some bonuses achieved with running BIND locally, such as setting your upstream DNS servers. For example, you may wish to use Google's public DNS instead of your ISP's, who may hijack things you type into your browser's address bar.

To Sum Up

With this setup, I am able to serve up a new PHP project with zero steps, a new Rails project with 1 step (create symlink), and a new node project with 2 steps (create symlink, start node). Not too bad, eh?

Happy local development!

Share Share on Twitter Share on Facebook Share on LinkedIn

How Can We Help?

Reaching out doesn’t mean you’re ready to start a project, but we’d love to learn more about the challenge you’re facing, answer any questions, and see if we might be a good fit for working together.

Contact Us