This one has been bugging me for a couple of years and I just didn’t want to put in the time and testing to nail it down. But tonight was my night.
The Problem
Here in my development palace I have a couple of laptops that I use for development and an Ubuntu (hardy) server as a Rails/Rack sandbox that I run with Passenger. While I have always been able to serve up either a Rails or Sinatra project, I typically have 3 or 4 going at the same time. But I had to access them with urls like: http://192.168.0.2/project1 and http://192.168.0.2/project2.
So, what’s the problem, eh?
Well, for starters, you can’t do anything concerning subdomains. That’s a show stopper for many apps.
Second, it really messes with your environment variables like [“PATH_INFO”]. So if you do any routing and you expect the base url to be ‘/’, it won’t be. The root url will be ‘/projectx’. Bummer.
The Solution
To remedy the issues with non-tld virtual hosts (also called sub URIs?) we need to add the domains to the laptops and server, then add the virtualhosts on the server for apache. This means that I can now goto http://project1.ubuntu.remote url to get to my rails/rack app.
For reference, I am using the following:
- Laptops: Mac OS X, 10.5.7 and 10.4.11
- Server: Ubuntu Desktop 8.04LTS, Apache/2.2.8 (Ubuntu) mod_fastcgi/2.4.6 PHP/5.2.4-2ubuntu5.5 with Suhosin-Patch Phusion_Passenger/2.0.6
On Each Laptop
These instructions are for Mac OS X, but should be identical for your favorite flavor of *nix. We are going to add some friendly names to our ubuntu server using it’s ip address (192.168.0.2). In this example we will be able to access the root web documents using http://ubuntu.remote, and one of our Sinatra projects using http://project1.ubuntu.remote.
Important! Don’t use a name ending in ‘.local’. While it did work for me, I read about a few instances where some systems will not resolve domain names ending in .local outside the local machine. Also, don’t change anything else in your /etc/hosts file except to add the lines at the end.
[source language=’python’]
mate /etc/hosts
# add the following line to the END of your /etc/hosts file and save
# note: there is a
192.168.0.2 ubuntu.remote project1.ubuntu.remote
[/source]
On The Server: Hosts File
Nothing will work until we tell the server machine that it can accept incoming traffic from our new friendly names. Similar to on the mac, we need to edit our /etc/hosts file but we will add a slightly different line. In this case we are telling the server that incoming traffic from ‘ubuntu.remote’ and ‘gems.ubuntu.remote’ are just names for the localhost (127.0.0.1).
[source lang=’shell’]sudo pico /etc/hosts
# add the following line to the end of our /etc/hosts file and save
# you can added after your existing 127.0.0.1 line if you wish
127.0.0.1 ubuntu.remote project1.ubuntu.remote
[/source]
On The Server: VirtualHosts
As a final step we will need to add or change the virtual host definitions for your rails/rack project. Depending on your Apache setup or Linux distro, the default enabled site may be slightly different and you may have to adapt your virtual host file to your default setup.
First, in my /etc/apache2/apache.conf file, I have the following line near the end of the file. This was to eliminate a warning every time apache was started/restarted. It may affect your virtual host default, but shouldn’t, so add it if you get errors.
[source lang=’shell’]
#added near end of /etc/apache2/apache.conf
ServerName localhost
[/source]
Next we need to check our default virtual host setup to see how the NameVirtualHost is defined. We will duplicate that in each new virtual host that we add. The parts we are looking is the NameVirtualHost and VirtualHost near the top. They could be ‘NameVirtualHost *’ and ‘<VirtualHost *>’ or ‘NameVirtualHost *:80’ and ‘<VirtualHost *:80>’. See the pattern? We need to use the same definition in our new virtual files.
Let’s check our default virtual host setup:
[source lang=’shell’]
cd /etc/apache2/sites-enabled
ls # your are looking for the name of your default site file
total 0
lrwxrwxrwx 1 root root 36 2009-02-27 18:49 000-default -> /etc/apache2/sites-available/default
cat /etc/apache2/sites-enabled/000-default
NameVirtualHost *
ServerAdmin webmaster@localhost
# snipped several lines #
[/source]
On my system the NameVirtualHost is ‘*’, so that is what we need to use for the new virtual host. In this case, I am going to add a virtual host file for a rack based project. It’s a Sinatra app, but that doesn’t matter as this will work for any rack based project, even a rails/rack project (since rails 2.2.2?).
Also, I like using the Apache2 system to enable and disable sites. It’s clean, easy to use, and if any apache admin comes along they will know exactly what is going on.
It’s also work mentioning that you should disable or delete any existing virtual host files that you were using previously.
[source lang=’shell’]cd /etc/apache2/sites-available
sudo pico gems
# enter this as your virtual host setup
ServerName project1.ubuntu.remote
DocumentRoot “/path/to/your/application/project/public”
RackEnv production
Order allow,deny
Allow from all
# save the file and reload apache
sudo /etc/init.d/apache2 reload
[/source]
The Fun Part
Assuming you saw no errors when you reloaded apache, you should be able to go to your new urls see both the root files and your rack application.
http://ubuntu.remote
http://project1.ubuntu.remote
Dyn-O-Mite!
Bonus Points!
For extra credit, let’s say you have admin access to your router, and you are one of those gotta-have-control-of-everything dudes (or dudettes) so you installed a 3rd party firmware. You’re in luck! You can probably add some custom entries in your DNS and you don’t have to edit the /etc/hosts files on your laptop.
I installed Tomato firmware on my Linksys wireless router. Tomato uses Dnsmasq with allows you to set internal host names.
Maybe I’ll cover that in another post.