Phusion Passenger integration question #258

Open
juanitogan opened this Issue Mar 18, 2014 · 29 comments

Projects

None yet

8 participants

@juanitogan

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:

    PassengerRuby /opt/rubies/ruby-1.9.3-p484/bin/ruby

Something like the following would be more ideal if it were possible:

    PassengerRuby $RUBY_ROOT/bin/ruby
@postmodern
Owner

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.

@juanitogan

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.

@postmodern
Owner

@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 ;)

@juanitogan

@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:

PassengerRubyVersion /webapps/appone/.ruby-version

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

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.

@postmodern
Owner

@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.

@postmodern
Owner

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.

@sandstrom

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!

@sandstrom sandstrom referenced this issue in phusion/passenger Jun 2, 2014
Closed

Support for `chruby` #1205

@FooBarWidget
Contributor

otherwise it uses this PassengerHelperAgent which I can't seem to find documentation on.

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.

However, I have not found this to be the case.

That's because the PATH in Nginx can be different from the one in your shell. Read up on how environment variables work.

@postmodern
Owner

If chruby is configured in ~/.bash_profile, you should enable passenger_load_shell_envvars so that bash -l -c is used to start the app.

@sandstrom

I've configured it in /etc/profile.d/chruby.sh, and passenger_load_shell_envvars is enabled (it's on by default).

The content of my chruby.sh is:

source /usr/local/share/chruby/chruby.sh
source /usr/local/share/chruby/auto.sh

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 ./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?

@postmodern
Owner

@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.

@postmodern
Owner

If that is the problem, I suspect explicitly calling chruby_auto after loading it would fix this.

@lowski
lowski commented 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 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>'
@FooBarWidget
Contributor

@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
lowski commented Oct 6, 2014

@FooBarWidget thanks but I read the whole documentation of chruby and I didn't find any section about environment variables that chruby expects. Could you point me to the right direction?

@FooBarWidget
Contributor

@postmodern Can you help out iowski?

@postmodern
Owner

@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.

@lowski
lowski commented 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
Owner

@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.

@lowski
lowski commented 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
Owner

@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.

@jlecour
Contributor
jlecour commented 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 :

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    passenger_root /usr/local/Cellar/passenger/4.0.53/libexec/lib/phusion_passenger/locations.ini;
    passenger_ruby /Users/jlecour/.rubies/ruby-2.1.2/bin/ruby;

    sendfile        on;
    keepalive_timeout  65;

    server {
       listen 8080;
       server_name my_app.local;
       root /Users/jlecour/Projects/my_app/public;

       passenger_enabled on;
       rack_env development;
    }
}

In ~/.zshrc and ~/.profile :

source /usr/local/share/chruby/chruby.sh
source /usr/local/share/chruby/auto.sh

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
Owner

@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.

@jrochkind

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

@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" "$@"

[path/to/nginx.config]

# Passenger Configuration
passenger_ruby /usr/local/bin/chruby-wrapper;
@OnixGH OnixGH referenced this issue in phusion/passenger Jan 8, 2016
Closed

Error in `passenger start` 5.0.X (standalone) #1719

@carukc
carukc commented 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

@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
Contributor

Passenger 5.0.24 will fix a bug related to environment variables. That bug could be the cause of some of your problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment