Deploying with rbenv and Capistrano

20 Feb 2012

UPDATE: I've updated the post to reflect changes in rbenv 0.4.0.

I've recently decided to move away from RVM in favor of rbenv. I thought RVM was a bit too finicky to use in production and I wanted something simpler that I could wrap my head around.

This post is more or less an attempt to collect what I figured out from reading an issue thread on GitHub, George Ornbo's great post about rbenv and the rbenv wiki page on deployment.

On the server

As the deployment user (in my case deploy), run the rbenv-installer:

$ curl -L https://raw.github.com/fesplugas/rbenv-installer/master/bin/rbenv-installer | bash

Add rbenv to your PATH. The second command adds shims and autocompletion:

$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.profile
$ echo 'eval "$(rbenv init -)"' >> ~/.profile

Reload the profile, install one or more rubies and then rehash to refresh the shims:

$ source ~/.profile
$ rbenv install 1.9.3-p327
$ rbenv rehash

Set your new rbenv ruby as the new system-wide default ruby for this user:

$ rbenv global 1.9.3-p327

Now it's time to go ahead and install your Passenger, Unicorn, or what have you.

Capistrano

Now, let's turn our attention to Capistrano and our deploy.rb.

We want Bundler to handle our gems and we want it to package everything locally with the app. The --binstubs flag means any gem executables will be added to <app>/bin.

require "bundler/capistrano"
set :bundle_flags, "--deployment --quiet --binstubs"

If you don't want to use a globally installed Bundler, you need to add a binstub for it manually and tell Capistrano to use that:

set (:bundle_cmd) { "#{release_path}/bin/bundle" }

The binstub itself (<app>/bin/bundle) should look like this:

#!/usr/bin/env ruby

require 'rubygems'
version = ">= 0"

if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
  version = $1
  ARGV.shift
end

gem 'bundler', version
load Gem.bin_path('bundler', 'bundle', version)

Since the .profile PATH settings we added earlier won't get run by Capistrano we need to add the rbenv paths to our deploy.rb. Note that we add the shims folder directly here instead of running rbenv init -. It's easier and autocomplete is wasted on Capistrano.

set :default_environment, {
  'PATH' => "$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH"
}

That's pretty much it.