Ruby 1.8 and Ruby 1.9 with Phusion Passenger and Apache (and Thin)

Migrating to Ruby 1.9 gets harder the more 1.8 apps you have. But it’s a worthwhile migration. At work we’ve written a lot of little Ruby 1.8 apps and we deploy them on an Apache + Phusion Passenger stack. Some apps run on their own domain but some run in subdirectories too. Here’s how we migrated to a joint 1.8 and 1.9 situation (for future development but legacy support) with as little adjustment to the apps themselves as possible.

Caveats and pre-requisites

Firstly, we’re using RVM. Doing this is probably a lot more complicated without RVM so I’m not going to go into that. You’re on your own. Additionally, we use Capistrano for deployment with the RVM plugin so we can specify what Ruby environment we want an app to be deployed under (e.g. for installed gems). I’m not sure what you’d need to do in a different deployment situation to ensure that gems, rake tasks etc. are run with the right Ruby version. Again, you’re on your own there!

How to do it

Phusion recommend that to run 1.8 apps alongside 1.9 apps you use the Apache module for one version and multiple instances of the standalone version of Phusion Passenger (which I think is basically just an instance of nginx). Because we want to start using 1.9 as standard I decided to have the Apache module running on 1.9 and use instances of the standalone version for 1.8 apps.

I gave this a try but discovered that Phusion Passenger Standalone doesn’t support subdirectories very well. You get into situations where the URLs coming out of your app (Rails or Sinatra) don’t have the subdirectory appended to them. So instead of using Phusion Passenger across the board, I switched to using Thin for the 1.8 apps which has support for deploying apps on a subdirectory.

To manage all the instances of Thin, I wrote a God config file:

base_dir = File.dirname(__FILE__)

apps = [
  "app1", #3000
  "app2", #3001
  "app3" #3002
]

prefixes = {
  "app1" => "/app1/",
  "app2" => "/somewhere/app2",
  "app3" => "/app3"
}

prefix = "/home/web/apps/"
# Count up from this port.
port = 3000

apps.each do |app|
  God.watch do |w|
    w.name = "thin-#{app}"
    w.group = "1.8.7-apps"
    # Capistrano deploy directory:
    w.dir = File.join prefix, app, "current"
    w.interval = 30.seconds

    w.log = File.join base_dir, "logs", "#{app}.log"

    if !DEVELOPMENT
      w.uid = 'web'
      w.gid = 'web'
    end

    w.env = { 'HOME' => '/home/web',
              'RACK_ENV' => 'production',
              'RAILS_ENV' => 'production',
              'RAILS_RELATIVE_URL_ROOT' => prefixes[app].chomp('/')
    }

    # Start command
    w.start = "bundle exec thin start -a 127.0.0.1 -p #{port} -e production --prefix=#{prefixes[app]}"
    w.start_grace = 10.seconds

    w.behavior(:clean_pid_file)

    w.start_if do |start|
      start.condition(:process_running) do |c|
        c.interval = 5.seconds
        c.running = false
      end
    end

  end
  port += 1
end

Each app has a configured endpoint and is assigned a port ascending from port 3000. Thin doesn’t start as a daemon, which allows God to manage it. Our apps run as the web user. Also because we use Bundler for all our apps Thin is executed in the Bundler environment, so the only change you need to make to the app itself is to add Thin to the Gemfile and redeploy.

So for each 1.8 app, the configuration in Apache originally looked like:

RackBaseURI /app1
<Directory /home/web/public_html/app1>
	Options -MultiViews
</Directory>

To  switch to using Thin:

<Location /app1>
  ProxyPass http://127.0.0.1:3000/app1
  ProxyPassReverse http://127.0.0.1:3000
  Options -MultiViews
</Location>

Note the need to add the endpoint to ProxyPass. I’m not 100% sure why this is necessary; possibly a combination of deploying Thin to a subdirectory and using Apache to reverse proxy to it.

Now, I installed Ruby 1.9 and re-installed the Phusion Passenger Apache module to run under 1.9. In every app from now on, we tell Capistrano to run using 1.9 instead of 1.8 and use an .rvmrc file to ensure that development occurs under 1.9.

This entry was posted in Blog, Noteworthy. Bookmark the permalink.