Using RVM rubies with Passenger 3
This page contains instructions for using RVM with Phusion Passenger 3. You really should upgrade to Phusion Passenger 4 or later because it comes with much better RVM support. See this page for Phusion Passenger 4 instructions.
Passenger 3
Passenger is essentially 'mod_ruby' for both Nginx and Apache. You may select *exactly one* Ruby to run all of your Passenger 3 applications. If you need to run more than one Ruby interpreter then you should choose the most common one. You then use proxy pass to external application servers such as Passenger Standalone, Unicorn, Thin, Mongrel, Mongrel2, etc... in order to accomplish running different applications under different rubies. For a full explanation of this (with pretty pictures!) see the post on Phusion's Blog
Installing Nginx/Apache with Passenger
First of all there's passenger-install-apache2-module and passenger-install-nginx-module. At the end of the installation it outputs a PassengerRuby configuration snippet for the web server. Its value is set to the RVM Ruby wrapper script that corresponds with the RVM Ruby and RVM gemset that was used to run the installer. This should be all you need for configuration of Passenger 3!
If you're still running into trouble instead of creating a .rvmrc file use one of the new formats like .ruby-version or .versions.conf:
echo 1.9.3@my-app-name > .ruby-version
Then in the rails project, add a new file config/setup_load_paths.rb and add Starting with RVM 1.12.0(or head) RVM is installed as a gem in default gemset, there is no need to unshift $LOAD_PATH, but it's required to set GEM_PATH. config/setup_load_paths.rb.
if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm') begin gems_path = ENV['MY_RUBY_HOME'].split(/@/)[0].sub(/rubies/,'gems') ENV['GEM_PATH'] = "#{gems_path}:#{gems_path}@global" require 'rvm' RVM.use_from_path! File.dirname(File.dirname(__FILE__)) rescue LoadError raise "RVM gem is currently unavailable." end end # If you're not using Bundler at all, remove lines bellow ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__)) require 'bundler/setup'
Please note that for Passenger 3 you now use the ruby wrapper script directly with no need to use the passenger_ruby wrapper.
Starting Passenger Standalone
Then there's Passenger Standalone, i.e. 'passenger start'. Passenger Standalone uses Nginx internally, and it writes a passenger_ruby directive to the Nginx configuration file. This directive points to the RVM Ruby wrapper script that corresponds with the RVM Ruby and RVM gemset that was used to run the 'passenger start' command.
Bundler Gotcha
When using Bundler in your project, Passenger will try to be smart and only add to your $LOAD_PATH the gems listed in your Gemfile. This can lead to "unable to load" errors for your unlisted gems (this should only happen during development). You can check your run-time load path by adding
f = File.open('/tmp/load_path', 'w') f.write($:) f.close
to your app's main file (before the "require" calls). You won't be able to load any gems that are not in that load path.
Troubleshooting
- The most common issue is forgetting the /bin/ part of the path to get the proper wrapper script:
-
The next most common issue is listening to the output of the passenger installation script with
respect to where the passenger_ruby/PassengerRuby is located. Be sure to use the wrapper script location
as specified above. To be more clear, see the nginx example below:
passenger_ruby /home/wayne/.rvm/bin/passenger_ruby; * NOTICE THE '.rvm/bin' DIR ^ ^ ^ * do NOT use the actual ruby binary in .rvm/rubies/{passenger_ruby}/bin/ruby * do not listen to passenger's output for passenger_ruby as passenger is not aware of rvm.
For system wide (root) installs the bin directory is /usr/local/rvm/bin instead:passenger_ruby /usr/local/rvm/bin/passenger_ruby;
FAQ
-
Q: Can I run multiple projects under passenger with each project on a different ruby version?
A: Passenger 3 only supports running under *one* Ruby, but you can get per-site/project behavior using a proxy pass.
-
Q: How do I use custom gemsets under passenger?
A: Without bundler you can either set environment variables yourself in your config.ru like:
ENV["GEM_HOME"]=%x{"source ~/.bash_profile ; rvm ree@pancake ; rvm gemdir"}.strip
A: With bundler: Install bundler outside any gemset, switch back to the gemset you wish to use and run bundle install and restart the application (by touching tmp/restart.txt). This works becase bundler stores absolute paths inside .bundle/environment.rb which will be loaded by bundler directly. If this doesn't work as expected, try running bundle install like so:
bundle install $BUNDLE_PATH
How can I use commands like passenger-status in conjunction with a user install but run them as root? Mainly the key to this is to use wildcards in the sudoers file as the following examples show.
/usr/bin/env GEM_PATH=* GEM_HOME=* PATH=* passenger-status
This is config/setup_load_paths.rb for RVM versions bellow 1.12.0.
if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm') begin rvm_path = File.dirname(File.dirname(ENV['MY_RUBY_HOME'])) rvm_lib_path = File.join(rvm_path, 'lib') # $LOAD_PATH.unshift rvm_lib_path require 'rvm' RVM.use_from_path! File.dirname(File.dirname(__FILE__)) rescue LoadError # RVM is unavailable at this point. raise "RVM ruby lib is currently unavailable." end end # Pick the lines for your version of Bundler # If you're not using Bundler at all, remove all of them # Require Bundler 1.0 ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__)) require 'bundler/setup' # Require Bundler 0/9 # if File.exist?(".bundle/environment.rb") # require '.bundle/environment' # else # require 'rubygems' # require 'bundler' # Bundler.setup # end