This post explains how I use nginx and dnsmasq in my development environment to streamline the process of working with several Rails projects.
The nature of my work means that I work on a large number of Ruby on Rails projects, and I often switch between them several times a day. Like most people, I was content with starting each rails server, with rails s, as and when I needed it.
However, this isn’t ideal for a couple of reasons. Firstly, domain names are often used in web applications, such as admin.myapp.com or company1.myapp.com. You can add domain names to your hosts file, but this feels like an unnecessary step when setting up new projects.
The second reason is relating to the port number: sometimes, callbacks from services such as Facebook don’t play nicely with port numbers in the URL. Also, from a purely aesthetic point of view, I don’t like port numbers in the URL, or having to type them out.
Starting up a rails server with rails s causes it to listen on port 3000 by default. You can only bind it to port 80 if you’re running as a privileged user, e.g. with rvmsudo. This doesn’t seem like a particularly good move.
My first attempt
For a long time, I used nginx as a web server built with Phusion Passenger as the rails app server. This worked well: I could have domains like app1.dev and app2.dev, and the rails app would spin up automatically as and when I visited the URL.
I’ve left that behind for two reasons:
It wasn’t very resource efficient, and processes for multiple rails apps would be running concurrently and unnecessarily.
It didn’t play nicely with multiple ruby versions and gemsets, which is absolutely essential when dealing with many rails apps.
Now, I’ve moved to a much simpler setup.
The solution: nginx proxy and dnsmasq
First of all, I created an nginx server that acted as a proxy for all requests, sending them to port 3000. I could then run rails s as normal to start a server, but could use nginx to allow requests on port 80, which would then be redirected to the rails server. Here’s my nginx config to do that:
Nice and simple. This is the default server, so any hosts that haven’t been explicitly named in another nginx server configuration will be proxied.
I then installed dnsmasq (sudo apt-get install dnsmasq on debian/ubuntu), which I use to skip the step of adding hosts to my /etc/hosts file. I then catch all domains that end in *.dev using the following config:
dnsmasq is extremely useful, and it’s now an essential part of my development environment.
I’d be interested to hear about other setups, because I’m always looking for optimisations. Feel free to drop a comment with your configurations.