Virtual Machine Routing

Suppose you have some virtual machines hosted by Linux KVM that you want to be able to access from other computers. For example, you want to be able to type "http://vmname/" in your web browser and access the web site hosted on that virtual machine. How do you do this?

Note: if you configure the virtual network to use DHCP, you might be able to avoid setting up separate DNS and DHCP servers, but I don't know for sure because I didn't try it. I wanted the extra control available when running separate servers.

First of all, you need to set up a DNS server to map the names to the IP addresses. A good resource for this is the Ubuntu Community Documentation on BIND9. You may need to configure the DNS server to forward requests for hostnames it doesn't know about to upstream DNS servers. The documentation refers to this as a hybrid primary master and caching configuration. Note that this DNS server will need a static IP address. If your router runs DD-WRT, this is quite easy to do in the "Services" tab.

Next, you will need to either manually set the IP address on the virtual machine or set up a DHCP server to assign the IP address. If you do the latter, you will need to assign the virtual machine a static IP address. Some good resources for this are the Ubuntu Community Documentation on dhcp3-server and the man page for dhcpd.conf. Make sure to configure the DHCP server to specify the new DNS server as the one for clients to use.

Now all you need to do is configure the host machine's kernel to route packets. You know how to use iptables, right? No? Have no fear! All you need to do is fire up virt-manager, right-click the host machine, click "Details", go to the "Virtual Networks" tab, and configure a routed network! If you replace the default network and give the new one the same name, you won't have to reconfigure any of your virtual machines. I was very impressed by how easy this was.

Lastly, if you have an existing router, you will need to add a static route for the host machine. I use DD-WRT for my router, and this was quite easy to do (Setup->Advanced Routing). I was also able to configure DNSMasq to forward specific DNS requests to the new DNS server by adding "server=/<subdomain name>/<DNS server IP address>" to the "Additional DNSMasq Options" box in the "Services" tab, so I didn't have to recofigure DNS on all of my other machines.

Configuration files for dhcp3-server and BIND9 are available here. Please take the time to understand what they do before using them.

Once the above is set up, adding support for a new virtual machine is as simple as adding entries for it to the DHCP and DNS servers. This is quite convenient for testing web applications, as you can simply set up a new virtual machine, install the web app's dependencies, and test it, all without cluttering up a real machine with a special version of Ruby, a handful of Ruby Gems, or whatever it is that the web app needs. Once you're done, just delete the VM!