Sorry this page looks weird. It was automatically migrated from my old blog, which had a different layout and different CSS.

Using rbenv in Production

I just switched to using rbenv in production so I could easily upgrade to Ruby 1.9.2-p290. 37signals uses rbenv in production like this:

Each app is isolated through disciplined use of RubyGems/Bundler-style binstubs. We start with the stubs Bundler generates (bundle install --binstubs) and change the shebang from #!/usr/bin/env ruby to usr/bin/env ruby-local-exec. Update your Capistrano recipes, Chef cookbooks, Bluepill config, etc to use these binstubs throughout.

This draws a solid line between your app and your ops, meeting at just a handful of binstubs.

Now executing /u/apps/basecamp/current/bin/unicorn uses the Ruby in /u/apps/basecamp/current/.rbenv-version and the Unicorn bundled in /u/apps/basecamp/current/Gemfile.lock. Your app is self-contained. Your ops tools no longer know or care whether you use Bundler or whether you’re on 1.8.7 or 1.9.3. Achievement unlocked.

Jeremy Kemper

Shebangs and binstubs

As far as I can tell, binstubs have two advantages:

However I couldn’t get the Rails runner to work via a binstub, and I don’t mind if my “ops tools” know about Bundler. So I decided to forgo the binstubs and stick with bundle exec. Since I’m using the same Ruby everywhere on the server, via rbenv global 1.9.2-p290, it’s fine.

But I did need to update my app’s scripts' shebangs to ruby-local-exec; for example script/rails:

#!/usr/bin/env ruby-local-exec
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.

APP_PATH = File.expand_path('../../config/application',  __FILE__)
require File.expand_path('../../config/boot',  __FILE__)
require 'rails/commands'


Don’t forget to re-install Passenger in your rbenv-managed Ruby, and rbenv rehash afterwards.

And on Apache, you’ll also need to update the Passenger configuration to use the new Ruby.

Non-app gems

You’ll also need to install (and rbenv rehash) non-Gemfile gems, such as those your crontab commands use. For example I use a gem via cron to backup the database to S3.


With rbenv managing Ruby, and Bundler managing my app’s gems, everything is nicely isolated. As Jeremey Kemper went on to say:

Now, say Ruby 1.9.3-rc1 just came out and you want to upgrade your app. Push the new package to your servers (using Chef or whatever), change .rbenv-version from 1.9.3-preview1 to 1.9.3-rc1, and cap deploy. That’s it.

Didn’t work out? cap deploy:rollback and you’re back at 1.9.3-preview1. Ahh.

Which is lucky, because my Rails 3.0.10 app takes a glacial 3m47s to start up on Ruby 1.9.2-p290. As my friend Kamyar says, that’s not a computer number: ~4 minutes on modern CPUs corresponds to gazillions of instructions and we are not modelling the climate here.

So I’m going to take advantage of my easily-upgradable environment and upgrade to 1.9.3-rc1 as soon as possible.

Andrew Stewart • 20 October 2011 • RubyDeployment
You can reach me by email or on Twitter.