LAN for web developers

Chris Hale by Chris Hale, 17 Jan 2014

WARNING: incredibly nerdy post - not for the faint hearted - does not include cat pictures.

For our last sprint, we were building a web based mobile application. This meant that we had to do a lot of testing on our mobile devices (ok... iPhones). Usually, this is a farily simple task. We would boot up a simple webserver such as Python's SimpleHTTPServer, or a Node server, switch on Wi-Fi on the device and visit our computer's local IP address with port number on the device.

We had set up static IP's on our BT home hub, to try and make this process a little easier. We then all had an IP address we could remember easily, should we have to test another team members version of the app.

192.168.1.101 --> Joe
192.168.1.102 --> Chris
192.168.1.103 --> Mac

After finishing the sprint we had a retrospective, and it turned out the whole process was a bit of a nightmare.

“We need a new router. BT Home Hub’s don’t cut it when you’re working in a development environment with static IPs and custom DNS settings.”

To sum up, these are some of the main problems we faced from that sprint:

To tackle this problem, we decided to use a DNS server to setup host names that resolved to each of our machines. This would give us a consistent format to the URLs we use for each project, whether it be a staticly served client side ui or a full rails stack.

So after a bit of research we opted to buy a new router and use an open source firmware called DD-WRT. We chose this because it runs a service called DNSmasq, which can be used to manually setup your own local DNS server. This allowed us to set up a local area network that suites us perfectly regardless of what technology stack we're using.

The finished setup

Here is a overview of what we're currently able to do from any device in our local area network.

Using Apache

So, if we're building a PHP site:

http://foo.chris/ resolves to 192.168.1.102 (My machine) which is picked up by Apache on port 80 and serves the files located in ~/Sites/foo/

This pattern is the same for all machines:

http://foo.joe/ resolves to 192.168.1.101 (Joe's machine) which is picked up by Apache on port 80 and serves the files located in ~/Sites/foo/

http://foo.mac/ resolves to 192.168.1.103 (Mac's machine) which is picked up by Apache on port 80 and serves the files located in ~/Sites/foo/

And for all folders:

http://bar.chris/ resolves to 192.168.1.101 (My machine) which is picked up by Apache on port 80 and serves the files located in ~/Sites/bar/

Using Node.JS and Rails

By default we run these on port 3000 or 5000 (if using foreman). Which means visiting:

http://chris:3000/ will resolve to 192.168.1.102 which is picked up by the Rails server running on port 3000 and serves the files.

Likewise if another team member were to have this on their machine:

http://mac:3000/ will resolve to 192.168.1.103 which is picked up by the Rails server running on port 3000 and serves the files.

Using Apache mod_proxy with Rails/Node.js

We've also experimented with using Apache's mod_proxy to route requests on port 80 to another port number e.g. 3000. Meaning we can keep the same format regardless of the technology stack:

http://railsapp.chris/ will resolve to 192.168.1.103 which is picked up by Apache on port 80 and route the request to port 3000 and the Rails server will serve the files.

Other devices

The beauty of this is that no matter what device you use (as long as it is connected via Wi-Fi or Ethernet to our router), will use the same DNS server to resolve these easy to remember host names. So we can just grab the office Android phone and quickly test something out without having to check IP addresses, oAuth callback urls etc.

How we did it

Before I start, I'll warn you this has only been tested with our setup (BT Home Hub and D-Link router running DD-WRT). I can't guarantee it will work for every combination of routers/modems. If you have any issues feel free to add a comment at the bottom and I'll try and help.

First step is get a router which supports DD-WRT (there are guides and lists of supported devices on the site).

We bought a D-Link router from eBay with the DD-WRT firmware pre installed for about £25. It supports 802.11n and has a 5 port ethernet switch. Alternativley you can install it directly on your modem/router (but we're a bit scared by that, so can't reccomend it).

Once it arrived, it was as simple as pluging it in and connecting it to our existing BT Home Hub modem with an ethernet cable.

Basic Setup

Once you have plugged everything in, you will need to connect a computer to the new router. I would suggest using ethernet (if possible), as I did end up locking my self out of connecting via Wi-Fi a couple of times.

If you visit the routers IP address (mine was 192.168.1.1) in your web browser of choice, you should see the DD-WRT control pannel:

The DD-WRT Control Panel

First thing would be to add an admin password for the router in Administration > Management and add a WPA key in Wireless > Wireless Security.

You will also need to change the Wireless Mode to be AP in Wireless > Basic Settings and possibly change your channel while your at it. Ours was using the same as the Home hub by default - resulting in a shitty slow wireless connection.

There are a lot more settings you can go through and change to match your LAN enviroment, but I'll just focus on the DNS settings.

DNS Setup

Click on Setup > Basic Setup, and you should see something like this:

The DD-WRT Control Panel > Basic Setup

Here we set the following:

[WAN Connection Type]
Connection Type: Disabled

[Router IP]
Gateway: <your exisiting modem/router IP address> (our home hub was 192.168.1.254)
Local DNS: 0.0.0.0

[WAN Port]
Assign WAN Port to Switch: yes

[Network Address Server Settings (DHCP)]
DHCP Type: DHCP Server
DHCP Server: Enable
Start IP Address: 192.168.1.100
Static DNS 1: 192.168.1.1 (the ip address of your new DD-WRT router)
Static DNS 2: 8.8.8.8
Static DNS 3: 8.8.4.4
WINS: 0.0.0.0
Use DNSMasq for DHCP: yes
Use DNSMasq for DNS: yes
DHCP-Authoritative: yes

Click on Save at the bottom, wait for the page to reload then click on Apply Settings.

DHCP server and DNSmasq

Click on Services > Services, and you should see something like this:

The DD-WRT Control Panel > Services

Here we set the following:

[DHCP Server]
Used Domain: LAN & WLAN
LAN Domain: strobe (or what ever you choose)

[DNSMasq]
DNSMasq: enable
Local DNS: disable
No DNS Rebind: disable

Next you will need to setup the static leases for the development machines, by adding their MAC addresses, hostname and IP addresses like so:

The DD-WRT Control Panel > Services

You will need to leave the Client Lease Time empty to make these static.

Now we'll set up the custom DNS settings in Additional DNSMasq Options:

address=/.joe/192.168.1.101
address=/.chris/192.168.1.102
address=/.mac/192.168.1.103

It makes sense here to match the host names you set up in the static leases, with the wildcard domains above.

Click on Save at the bottom, wait for the page to reload then click on Apply Settings.

Your new router should be all setup and ready to go. You can test everything is working by trying out a few of the host names in your browser and confirming they point to the correct machines.

Working away from the router

All of this works well as long as you are connected in some way to the router. But in a situation where you are away from the office (perhaps at home or even thethering from a 3G connection), the hostnames we've set up will not resolve. Because there is no DNS server to tell them where to go.

Luckily we can install DNSmasq on each of the development machines as well. On a Mac, this can be done with:

brew install dnsmasq

You will then to configure it locally so your own hostname, resolves to your local IP of 127.0.0.1:

mkdir -pv $(brew --prefix)/etc/
echo 'address=/.chris/127.0.0.1' > $(brew --prefix)/etc/dnsmasq.conf
sudo cp -v $(brew --prefix dnsmasq)/homebrew.mxcl.dnsmasq.plist /Library/LaunchDaemons
sudo launchctl load -w /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist
sudo mkdir -v /etc/resolver
sudo bash -c 'echo "nameserver 127.0.0.1" > /etc/resolver/dev'
# taken from http://www.echoditto.com/blog/never-touch-your-local-etchosts-file-os-x-again

Fin.

If you have any issues setting any of this up, feel free to leave a comment below. I'll try my best to help!

comments powered by Disqus