You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
What is the best practice for integrating chruby with Phusion Passenger? Is there one?
I have chruby auto switching enabled at the system level and it would be nice to not have to hard code the passenger line in ssl.conf (and/or httpd.conf) in addition to maintaining .ruby-version. For example, from my ssl.conf:
auto-switching breaks down for things that do not use the shell (cron, apache, etc). I recommend simply installing your desired ruby via the package manager or into /usr/local via ruby-install. The beauty of /usr/local is it's already in $PATH, so no additional configuration needed.
Thanks. Problem is we already have another ruby in the path in /usr/bin that I need to ignore so I'm stuck with the default of /opt/rubies. Personally, I don't know where the best place is to put the app server rubies. I noticed that, by default, root does not have /usr/local in its path on our setup, and, of course, not /opt either.
@juanitogan/usr/local/bin typically should precede /usr/bin in $PATH. You can also specify the absolute path to /opt/rubies/. Also, you probably should avoid running apps under root ;)
@postmodern Thank you, I agree on all those points. I can't say I know a lot about Linux but I have figured that much out. I believe the main app owner runs the app (according to settings I see in ssl.conf). I'm just not sure about who boots up the machine and starts httpd and all that (I believe I saw in some docs that Passenger runs as nobody). I've been using sudo bash to setup chruby and everything else but don't have any more control than that to change the low-level stuff.
I presume I could try setting a default ruby for the app user to simplify the PassengerRuby line, but then if I needed to run more than one ruby version as this app grows or splits into multiple apps, I would be back to hard coding the PassengerRuby line(s). I'm trying to establish the best practice for all future Ruby development here so I need to stick with what will work in most scenarios. [Yes, a bit odd that this fell to me who has little Linux and Ruby experience but, well, probably best if I don't explain that further.]
I suspect the only way to do what I was hoping for is for Passenger to add support for .ruby-version themselves. Such as:
Anyhow, I just had to ask these questions just to be sure I wasn't missing something. Thank you for your help. And thank you, especially, for chruby and ruby-install -- they are much nicer than RVM to use (after I finally solved that annoying OpenSSL thing).
While investigating how Passenger sets the user I discovered the answer to my question. Set PassengerDefaultRuby to the default value of "ruby" (or don't set it at all):
PassengerDefaultRuby ruby
This tells Passenger to find Ruby through the path. Therefore, because Passenger starts the app as the user who owns config.ru and starts up in the same folder as .ruby-version, chruby executes and sets the path to the correct Ruby version.
Note: do not set PassengerRuby at all in this case unless you need to override the autoswitching that .ruby-version does.
@juanitogan fascinating! Did you confirm passenger actually started rackup in a shell with chruby loaded? If this is the case, create a Wiki page for Passenger ASAP and I'll link it in the README.
Double checking the [Passenger Documentation](http://www.modrails.com/documentation/Users guide Apache.html), you should also enable PassengerLoadShellEnvvars to ensure the application is loaded via bash -l -c ..., otherwise it uses this PassengerHelperAgent which I can't seem to find documentation on.
I dug in this recently, thought I'd add a note here. Also, chruby is awesome! Thanks @postmodern!
For Passenger Nginx the following is stated (Passenger 4.0 and later):
The passenger_ruby directive in the http block is also used as the default Ruby interpreter for Ruby web apps. You don’t have to specify a passenger_ruby in the http block though, because the default is to use the first ruby command found in $PATH.
However, I have not found this to be the case. It seems to use the OS-level ruby, unless I manually run chruby ruby-2.1.2 before, e.g. in /etc/profile.d/chruby.sh.
If anyone has got this working with nginx/passenger without setting the ruby version globally I'm super-happy to hear about it!
With rack apps the web root (in nginx) is often set to the ./public sub-directory, but I think the auto script traverses upwards until it hits a .ruby-version file, so I'm thinking it should work.
Perhaps there is something I've overlooked or misunderstood?
@sandstrom one issue could be whether passenger cds into the directory before spawning the sub-shell, or within the sub-shell. chruby_auto only executes after the command, so bash -l -c 'rackup' would not automatically switch until after the first command.
I also have question about integrating chruby with Phusion Passenger. Right now if I don't include auto switch script on system level (/etc/profile.d/chruby.sh) then my app won't start - it can not find bundler, even though it has PassengerRuby specified in Apache virtual host.
This is the error I got:
Error ID: 3150c494
Error details saved to: /tmp/passenger-error-QHRe7r.html
Message from application: cannot load such file -- bundler/setup (LoadError)
/home/deployer/.rubies/ruby-2.1.3/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
/home/deployer/.rubies/ruby-2.1.3/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
/usr/lib/ruby/vendor_ruby/phusion_passenger/loader_shared_helpers.rb:263:in `block in run_load_path_setup_code'
/usr/lib/ruby/vendor_ruby/phusion_passenger/loader_shared_helpers.rb:366:in `running_bundler'
/usr/lib/ruby/vendor_ruby/phusion_passenger/loader_shared_helpers.rb:261:in `run_load_path_setup_code'
/usr/share/passenger/helper-scripts/rack-preloader.rb:100:in `preload_app'
/usr/share/passenger/helper-scripts/rack-preloader.rb:158:in `<module:App>'
/usr/share/passenger/helper-scripts/rack-preloader.rb:29:in `<module:PhusionPassenger>'
/usr/share/passenger/helper-scripts/rack-preloader.rb:28:in `<main>'
@lowski That's because you haven't set the proper chruby environment variables. You should read the documentation about what environment variables chruby expects. Then you must configure Phusion Passenger to make sure they're set. You can double check your environment variables by reading the error details dump file ("Error details saved to: ...filename...").
@lowski I am guessing that you installed bundler as a normal user via chruby, so it should be installed in ~/.gem/.... Try installing bundler as root via chruby, so the bundler gem is installed into the rubies main gem dir.
@postmodern how can I install bundler as root? If I log in as root and install bundler, chruby will pick it up and place it /home/root/.gem/... am I right?
@lowski as stated in the Features, chruby does not set GEM_HOME when running as root, and merely let's rubygems use it's default gem dir (which is typically inside the ruby installation). When running as a normal user, GEM_PATH contains both ~/.gem/... and the default gem dir.
@postmodern in that case it won't conflict with system Ruby version?
I'm sorry if all those questions are stupid but I'm a little bit confused (that's my first time with chruby on the server - previously I used rbenv and I didn't have this issue.). I installed ruby inside /home/deployer/.rubies. Apache is running as deployer user with ruby path pointed to .rubies in the deployer's home folder. I don't use the Ruby that comes with Ubuntu so why should I install bundler gem for the system Ruby version?
@lowski nope, it should not. RubyGem's default gem directory is always somewhere inside of the ruby installation. You should consider installing ruby into /opt/rubies so it's globally accessible. Also, you really don't need chruby on the server. I typically just use BrightBox's packages or install into /usr/local with ruby-install.
When I load my app in the browser, I dont get the Bundler exception, but a missing gem and a message telling me to bundle install. Obviously my Gemfile is properly installed (the Rails console is working).
The Passenger error page gives me the environment where I can find the GEM_HOME and GEM_PATH (which seem to be correct).
@jlecour I believe you have to specify which user you want passenger to run the app as. Also, specifying passenger_ruby causes passenger to not use the ruby available in $PATH.
Was there a consensus on best practice for using passenger with chruby, at the end of this discussion? @FooBarWidget or @postmodern ? I kinda know my way around the shell, but if someone's already figured it out, it would be super helpful. A wiki page?
@jrochkind here is a quick extraction from our chef receipt.
It's in pieces, because I had to cut away specifics, but hopefully it's enough to put you on the right track. Everything besides what's below should be the basics, i.e. default chruby, nginx and passenger installs. Hope it helps!
One caveat is that I think the latest version of Passenger (raptor) uses login shells in a different way [or doesn't use them anymore]. I remember @FooBarWidget telling me around the shellshock/bashdoor issue, that their version would work different in this regard. Perhaps someone more knowledgable can fill in details on this, I'm curious since we'll upgrade at some point.
/etc/profile.d/chruby.sh (owned by root)
if [ -n "$BASH_VERSION" ] || [ -n "$ZSH_VERSION" ]; then
source /usr/local/share/chruby/chruby.sh
# auto-switching is used for login shells, but not by
# passenger or cron jobs. See `chruby-wrapper` for details.
source /usr/local/share/chruby/auto.sh
fi
/usr/local/bin/chruby-wrapper (owned by root)
#!/bin/bash
source /usr/local/share/chruby/chruby.sh
source /usr/local/share/chruby/auto.sh
# calling `chruby_auto` after loading is needed in certain cases
# https://github.com/postmodern/chruby/issues/258#issuecomment-44897142
chruby_auto
# original call
exec "ruby" "$@"
The script seems to work fine on Passenger 5 on nginx but make sure that your site is located within the home directory of the passenger user (passenger_user in the site configuration file).
We've used the "chruby-wrapper" from @sandstrom's comment in production for years.
During a recent Ruby upgrade (3.2 -> 3.4), I was having trouble with errors such as "You have already activated base64 0.2.0, but your Gemfile requires base64 0.3.0". The PassengerPreloadBundler directive is supposed to address these kinds of issues, but it didn't work. Deeper investigation revealed that this is because it causes passenger to append " -r bundler/setup" to RUBYOPT, but RUBYOPT gets unset by the "chruby_auto" function.
The solution was to set RUBYOPT directly in the chruby-wrapper, after calling chruby_auto().
@jrochkind We're on bundler 2.7.2. I did the Ruby 3.4 installation + rubygems update last month, though, and it looks like bundler 4 (stable) was just released on Dec 3rd.
Activity
postmodern commentedon Mar 21, 2014
auto-switching breaks down for things that do not use the shell (cron, apache, etc). I recommend simply installing your desired ruby via the package manager or into
/usr/localvia ruby-install. The beauty of/usr/localis it's already in$PATH, so no additional configuration needed.juanitogan commentedon Mar 26, 2014
Thanks. Problem is we already have another ruby in the path in
/usr/binthat I need to ignore so I'm stuck with the default of/opt/rubies. Personally, I don't know where the best place is to put the app server rubies. I noticed that, by default, root does not have/usr/localin its path on our setup, and, of course, not/opteither.postmodern commentedon Mar 26, 2014
@juanitogan
/usr/local/bintypically should precede/usr/binin$PATH. You can also specify the absolute path to/opt/rubies/. Also, you probably should avoid running apps under root ;)juanitogan commentedon Mar 26, 2014
@postmodern Thank you, I agree on all those points. I can't say I know a lot about Linux but I have figured that much out. I believe the main app owner runs the app (according to settings I see in
ssl.conf). I'm just not sure about who boots up the machine and starts httpd and all that (I believe I saw in some docs that Passenger runs asnobody). I've been usingsudo bashto setup chruby and everything else but don't have any more control than that to change the low-level stuff.I presume I could try setting a default ruby for the app user to simplify the
PassengerRubyline, but then if I needed to run more than one ruby version as this app grows or splits into multiple apps, I would be back to hard coding thePassengerRubyline(s). I'm trying to establish the best practice for all future Ruby development here so I need to stick with what will work in most scenarios. [Yes, a bit odd that this fell to me who has little Linux and Ruby experience but, well, probably best if I don't explain that further.]I suspect the only way to do what I was hoping for is for Passenger to add support for
.ruby-versionthemselves. Such as:Anyhow, I just had to ask these questions just to be sure I wasn't missing something. Thank you for your help. And thank you, especially, for chruby and ruby-install -- they are much nicer than RVM to use (after I finally solved that annoying OpenSSL thing).
juanitogan commentedon Apr 4, 2014
While investigating how Passenger sets the user I discovered the answer to my question. Set PassengerDefaultRuby to the default value of "ruby" (or don't set it at all):
This tells Passenger to find Ruby through the path. Therefore, because Passenger starts the app as the user who owns
config.ruand starts up in the same folder as.ruby-version, chruby executes and sets the path to the correct Ruby version.Note: do not set
PassengerRubyat all in this case unless you need to override the autoswitching that.ruby-versiondoes.postmodern commentedon Apr 4, 2014
@juanitogan fascinating! Did you confirm passenger actually started
rackupin a shell with chruby loaded? If this is the case, create a Wiki page for Passenger ASAP and I'll link it in the README.postmodern commentedon Apr 4, 2014
Double checking the [Passenger Documentation](http://www.modrails.com/documentation/Users guide Apache.html), you should also enable PassengerLoadShellEnvvars to ensure the application is loaded via
bash -l -c ..., otherwise it uses thisPassengerHelperAgentwhich I can't seem to find documentation on.sandstrom commentedon May 30, 2014
I dug in this recently, thought I'd add a note here. Also, chruby is awesome! Thanks @postmodern!
For Passenger Nginx the following is stated (Passenger 4.0 and later):
However, I have not found this to be the case. It seems to use the OS-level ruby, unless I manually run
chruby ruby-2.1.2before, e.g. in/etc/profile.d/chruby.sh.If anyone has got this working with nginx/passenger without setting the ruby version globally I'm super-happy to hear about it!
FooBarWidget commentedon Jun 2, 2014
PassengerHelperAgent is the Passenger's core process, where most stuff happens. See https://github.com/phusion/passenger/wiki/Debugging-application-startup-problems#the-spawning-process-explained for a description of the spawning pipeline.
That's because the PATH in Nginx can be different from the one in your shell. Read up on how environment variables work.
postmodern commentedon Jun 2, 2014
If chruby is configured in
~/.bash_profile, you should enable passenger_load_shell_envvars so thatbash -l -cis used to start the app.sandstrom commentedon Jun 2, 2014
I've configured it in
/etc/profile.d/chruby.sh, andpassenger_load_shell_envvarsis enabled (it's on by default).The content of my
chruby.shis:It seems like the working directory is set to the 'web root':
https://github.com/phusion/passenger/blob/ec926a662ed5e8c501dfca65aa0c97c9e0a5d588/ext/common/ApplicationPool2/SmartSpawner.h#L232
With rack apps the web root (in nginx) is often set to the
./publicsub-directory, but I think the auto script traverses upwards until it hits a.ruby-versionfile, so I'm thinking it should work.Perhaps there is something I've overlooked or misunderstood?
postmodern commentedon Jun 2, 2014
@sandstrom one issue could be whether passenger
cds into the directory before spawning the sub-shell, or within the sub-shell. chruby_auto only executes after the command, sobash -l -c 'rackup'would not automatically switch until after the first command.postmodern commentedon Jun 2, 2014
If that is the problem, I suspect explicitly calling
chruby_autoafter loading it would fix this.lcmen commentedon Oct 6, 2014
I also have question about integrating chruby with Phusion Passenger. Right now if I don't include auto switch script on system level (/etc/profile.d/chruby.sh) then my app won't start - it can not find bundler, even though it has
PassengerRubyspecified in Apache virtual host.This is the error I got:
FooBarWidget commentedon Oct 6, 2014
@lowski That's because you haven't set the proper chruby environment variables. You should read the documentation about what environment variables chruby expects. Then you must configure Phusion Passenger to make sure they're set. You can double check your environment variables by reading the error details dump file ("Error details saved to: ...filename...").
2 remaining items
postmodern commentedon Oct 6, 2014
@lowski I am guessing that you installed bundler as a normal user via chruby, so it should be installed in
~/.gem/.... Try installing bundler as root via chruby, so the bundler gem is installed into the rubies main gem dir.lcmen commentedon Oct 7, 2014
@postmodern how can I install bundler as root? If I log in as root and install bundler, chruby will pick it up and place it
/home/root/.gem/...am I right?postmodern commentedon Oct 7, 2014
@lowski as stated in the Features, chruby does not set
GEM_HOMEwhen running as root, and merely let's rubygems use it's default gem dir (which is typically inside the ruby installation). When running as a normal user,GEM_PATHcontains both~/.gem/...and the default gem dir.lcmen commentedon Oct 7, 2014
@postmodern in that case it won't conflict with system Ruby version?
I'm sorry if all those questions are stupid but I'm a little bit confused (that's my first time with chruby on the server - previously I used rbenv and I didn't have this issue.). I installed ruby inside /home/deployer/.rubies. Apache is running as deployer user with ruby path pointed to .rubies in the deployer's home folder. I don't use the Ruby that comes with Ubuntu so why should I install bundler gem for the system Ruby version?
postmodern commentedon Oct 7, 2014
@lowski nope, it should not. RubyGem's default gem directory is always somewhere inside of the ruby installation. You should consider installing ruby into
/opt/rubiesso it's globally accessible. Also, you really don't need chruby on the server. I typically just use BrightBox's packages or install into/usr/localwith ruby-install.jlecour commentedon Oct 9, 2014
Hi,
I have a similar problem with Passenger + Chruby, but installed as "normally" (not server-wide).
I'm on Mac OS X 10.9, with Passenger 4.0.53 and Chruby 0.3.8.
My nginx.conf :
In
~/.zshrcand~/.profile:When I load my app in the browser, I dont get the Bundler exception, but a missing gem and a message telling me to
bundle install. Obviously my Gemfile is properly installed (the Rails console is working).The Passenger error page gives me the environment where I can find the GEM_HOME and GEM_PATH (which seem to be correct).
postmodern commentedon Oct 12, 2014
@jlecour I believe you have to specify which user you want passenger to run the app as. Also, specifying
passenger_rubycauses passenger to not use the ruby available in$PATH.jrochkind commentedon Mar 17, 2015
Was there a consensus on best practice for using passenger with chruby, at the end of this discussion? @FooBarWidget or @postmodern ? I kinda know my way around the shell, but if someone's already figured it out, it would be super helpful. A wiki page?
sandstrom commentedon Mar 17, 2015
@jrochkind here is a quick extraction from our chef receipt.
It's in pieces, because I had to cut away specifics, but hopefully it's enough to put you on the right track. Everything besides what's below should be the basics, i.e. default
chruby,nginxandpassengerinstalls. Hope it helps!One caveat is that I think the latest version of Passenger (raptor) uses login shells in a different way [or doesn't use them anymore]. I remember @FooBarWidget telling me around the shellshock/bashdoor issue, that their version would work different in this regard. Perhaps someone more knowledgable can fill in details on this, I'm curious since we'll upgrade at some point.
/etc/profile.d/chruby.sh (owned by root)
/usr/local/bin/chruby-wrapper (owned by root)
[path/to/nginx.config]
carukc commentedon Jan 23, 2016
The script seems to work fine on Passenger 5 on nginx but make sure that your site is located within the home directory of the passenger user (passenger_user in the site configuration file).
sandstrom commentedon Jan 23, 2016
@carukc Yes, but we're running 4.x, so I haven't tried in 5.x.
I'd peruse the docs for any changes that could have affected this in the 4 → 5 transition.
FooBarWidget commentedon Jan 25, 2016
Passenger 5.0.24 will fix a bug related to environment variables. That bug could be the cause of some of your problems.
speckins commentedon Dec 11, 2025
We've used the "chruby-wrapper" from @sandstrom's comment in production for years.
During a recent Ruby upgrade (3.2 -> 3.4), I was having trouble with errors such as "You have already activated base64 0.2.0, but your Gemfile requires base64 0.3.0". The PassengerPreloadBundler directive is supposed to address these kinds of issues, but it didn't work. Deeper investigation revealed that this is because it causes passenger to append " -r bundler/setup" to RUBYOPT, but RUBYOPT gets unset by the "chruby_auto" function.
The solution was to set RUBYOPT directly in the chruby-wrapper, after calling chruby_auto().
jrochkind commentedon Dec 11, 2025
@speckins, I'm curious, can you confirm you are still on bundler 2, or did the recent ruby update happen to get you bundler 4.0 as well?
speckins commentedon Dec 11, 2025
@jrochkind We're on bundler 2.7.2. I did the Ruby 3.4 installation + rubygems update last month, though, and it looks like bundler 4 (stable) was just released on Dec 3rd.