Passing environment variables to Ruby from Phusion Passenger
Update May 9 2013: The steps in this article are no longer always necessary. In Phusion Passenger 4, using SetEnv and PassEnv in Apache works as expected. In Nginx you can use the `env` option. Although you cannot customize `env` on a per-server basis, it works as expected.
Phusion Passenger manages Ruby/Rails process automatically. Sometimes it is necessary set environment variables or to pass environment variables to the Ruby interpreter. This particular aspect of Phusion Passenger isn’t very well documented, so it’s time for a blog post.
Environment variables that may be set after Ruby is started
Some environment variables may be set before or after Ruby is started. These include:
- PATH
- The search path for binaries.
- LD_LIBRARY_PATH
- The search path for shared libraries.
It really doesn’t matter where these environment variables are set, as long as you set them before you use them. These variables may be set in environment.rb or, if you’re using Apache, using the SetEnv directive.
Setting PATH, LD_LIBRARY_PATH and similar variables
Suppose that your environment.rb runs the program “frobnicate”, and this program is located in /opt/frobnicator/bin, which is not in PATH by default. Furthermore, the “frobnicate” program requires shared libraries which are located in /opt/awesome_runtime/lib. Suppose your environment.rb current looks like this:
...
Rails::Initializer.run do |config|
...
end
...
system("frobnicate") # => ERROR: command not found
Set PATH just before the system() call so that it can find the program:
ENV['PATH'] = "#{ENV['PATH']}:/opt/frobnicator/bin"
system("frobnicate") # => ERROR: cannot load libawesome_runtime.so
Now set LD_LIBRARY_PATH so that the program can find its libraries:
ENV['PATH'] = "#{ENV['PATH']}:/opt/frobnicator/bin"
ENV['LD_LIBRARY_PATH'] = "#{ENV['LD_LIBRARY_PATH']}:/opt/awesome_runtime/lib"
system("frobnicate") # => success!
On Apache you can also use the SetEnv directive instead of hardcoding such settings your app:
# Outside any virtual host block: SetEnv PATH /usr/bin:/usr/local/bin:/bin:/opt/frobnicator/bin SetEnv LD_LIBRARY_PATH /opt/awesome_runtime/lib
Setting GEM_PATH, the RubyGems search path
If you’re on a shared host (e.g. Dreamhost) or on some other server for which you do not have root privileges, then you have no choice but to install gems to somewhere inside your home folder. You also need to tell RubyGems to look in there, and that’s what GEM_PATH is for.
Suppose that you’ve installed the gem “ruby-frobnicator” into /home/foobar/my_gems. In your environment.rb you must set GEM_PATH and call Gem.clear_paths just before requiring the gem, like this:
...
Rails::Initializer.run do |config|
...
end
...
ENV['GEM_PATH'] = "/home/foobar/my_gems:#{ENV['GEM_PATH']}"
Gem.clear_paths
require 'ruby-frobnicator' # => it works!
Environment variables that must be set before Ruby is started
Some environment variables must be set before Ruby is started because the Ruby interpreter itself uses them. The RailsBench GC settings environment variables, which are now supported by Ruby Enterprise Edition, are examples of such environment variables.
You can set these environment variables by writing a wrapper script. Recall that Phusion Passenger has a “PassengerRuby” configuration option which typically looks like this:
PassengerRuby /usr/bin/ruby
You can point this to a wrapper script:
PassengerRuby /usr/local/my_ruby_wrapper_script
/usr/local/my_ruby_wrapper_script can set the environment variables prior to executing the real Ruby interpreter:
#!/bin/sh export RUBY_HEAP_MIN_SLOTS=10000 export RUBY_HEAP_SLOTS_INCREMENT=10000 export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1.8 export RUBY_GC_MALLOC_LIMIT=8000000 export RUBY_HEAP_FREE_MIN=4096 exec "/usr/bin/ruby" "$@"
A few notes for those who are not familiar with writing shell scripts:
- Make sure you make /usr/local/my_ruby_wrapper_script executable with chmod +x.
- Make sure that you prepend the “export” keyword to all environment variable setter statements.
- The last line says “replace the current process with /usr/bin/ruby, and pass all commandline argument that I’ve received to Ruby”. Make sure that $@ is wrapped inside double quotes, otherwise filenames with spaces in them won’t be passed correctly to the Ruby interpreter.
But wait, I’ve already set environment variables in my /etc/bashrc or /etc/profile. Why don’t they work?
If you’ve set environment variables in your /etc/bashrc or /etc/profile, then these environment variables are made available in your shell. However, on most operating systems, Apache is not started from the shell and does not load environment variables defined in bashrc/profile, which is why setting environment variables in /etc/bashrc and /etc/profile usually has no effect on Apache (and by induction, on Passenger and Rails processes).
Final words
This is just a quick blog post which I’ve written after seeing many people asking questions on this subject. This subject deserves proper official documentation, but I haven’t had the time to do it yet. If anybody wants to submit a documentation patch then please feel free to do so. In the long term it would probably be nice if one can pass environment variables to the Ruby interpreter via Apache configuration options, but it’s not a very high priority issue at this moment.
var addthis_config = {"data_track_clickback":true,"data_ga_property":"UA-32583440-3","data_ga_social":true,"data_track_addressbar":false,"data_track_textcopy":false,"ui_atversion":"300","ui_508_compliant":true}; var addthis_product = 'wpp-3.1';
Phusion. All rights reserved.
Pingback: passenger and rmagick on shared hosting « dimas priyanto
Pingback: … So We Built One :: ImageScience, FreeImage, and Dreamhost PS
Pingback: almost effortless » Weekly Digest, 11-6-09
Pingback: ImageMagick 和 Rmagick 之灵异事件 - 噏 【Up】
Pingback: passenger and rmagick on shared hosting « dimas priyanto
Pingback: Ruby on Rails Shared Hosting Gem Issue
Pingback: Rails ENV when using Phusion Passenger « Only The Wind Knows
Pingback: Visoft, Inc. Blogs | Ruby on Rails Shared Hosting Gem Issue
Pingback: Ruby Garbage Collector Performance Tuning | Carpe Diem
Pingback: rails3 unbearably slow view rendering: use REE with GC tuning | Bibliographic Wilderness
Pingback: Tales from upgrading to Ruby 1.9.2 - character encoding
Pingback: Installing phusion passenger with apache2 on Ubuntu « Exploring myself…