Update June 4 2013: This article is completely obsolete. In Phusion Passenger 4, using SetEnv and PassEnv in Apache and env in Nginx works as expected. Detailed information can be found in the Phusion Passenger manual, section “About environment variables”.

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:

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:

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:

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.

Thanks for the useful, linkable clarification. One additional note: sometimes, LD_LIBRARY_PATH falls into the category of environment variables which are used by the interpreter itself. (One example of this is when you are using the ruby-oci8 driver to talk to an oracle database in your rails app.) In this case, you’ll need to use the wrapper script method to set LD_LIBRARY_PATH.

Luke Redpath

I know there is an open ticket on this, but it would be nice if you could set environment variables using mod_env’s SetEnv directive instead.

Per Velschow

If you are on a shared host, you cannot change the PassengerRuby configuration option. Is there any other way to control which version of Ruby and more importantly RubyGems to be used? Or are you stuck on the versions installed by the host?

Since you mention DreamHost, I can say that they currently (on my server at least) have a very old Ruby installed: 1.8.5 (2006-08-25) and until recently also an outdated version of RubyGems. An ability to control these from a .htaccess file would be much appreciated.

@Andy: There are many things on our todo list which have higher priority than fixing the perceived messiness of setting environment variables. We’ll get there eventually but not right now. If you wish that this particular issue is addressed more quickly, then we’d be more than happy to accept a patch or to discuss a sponsorship campaign with you.

I was using the same solution as recommended here. But now I am trying a little bit cleaner approach.

If you have root access to server then in Linux case you can modify envvars file (see apachectl source to find file location on your system) to include environment variables that should be set up before Apache is started.

And in Mac OS X you can modify file /System/Library/LaunchDaemons/org.apache.httpd.plist to include EnvironmentVariables entry with dictionary of additional environment variables.

If you are redhat/centos/fedora user, you can add the lines to /etc/sysconfig/httpd. I’m sure other OSes have similar functionality. You could also add it directly to init scripts, but they have the potential to be overwritten with package updates.

FYI for all of you Dreamhost users out there, for some cases, some compile-time magic can remove the necessity of setting LD_LIBRARY_PATH during run-time.

In my particular case, it was the taf2-curb gem (cURL bindings for ruby) that refused to work. It would compile fine if I passed it the location of my custom install of the curl libs (i.e. “gem install taf2-curb — –with-curl-dir=/my/path/to/custom/libcurl”) but when I went to use it, it couldn’t find the curl libraries.

I spent hours trying to set LD_LIBRARY_PATH via SetEnv directives, environment.rb entries, etc. etc. but what fixed it was this:

A simple setting of LD_RUN_PATH before doing the gem compile/install mentioned above (“export LD_RUN_PATH=/my/path/to/custom/libcurl”) fixed the location of the libraries for the gem and it “Just Works” (after hours of misery).

My guess is that it would work for anything else (i.e. the ruby-oci8 driver, etc.) if you can build it yourself.

You saved the day! Thanks a lot! I’ve been trying to install “taf2-curb” on a dreamhost machine, finally I managed to install it. I set the “LD_RUN_PATH” and “LD_LIBRARY_PATH” with export, and also added to .bash_profile and .bashrc. Then, complied the taf2-curb, and copied “curb_core.so” from ext directory to the “lib” folder of taf2-curb gem.

I don’t think this has been documented anywhere else better than this blog post?

Regarding REE GC tuning env, it looks like recent versions of passenger under RVM install using a wrapper with an ‘environment’ file already. For instance, wrapper (included as PassengerRuby in passenger apache output) at:

/usr/local/rvm/wrappers/ree-1.8.7-2011.03/ruby

and that script already sources a bash file setting ENV at:

/usr/local/rvm/environments/ree-1.8.7-2011.03

So i think REE GC tuning env can conveniently be put in that ../environments/… file? Not sure if ‘export’ is needed, I think it’s not, but I used it anyway just to be safe.

“Phusion” and “Phusion Passenger” are registered trademarks of Phusion. “Rails”, “Ruby on Rails” and the Rails logo are registered trademarks of David Heinemeier Hansson. All other trademarks are property of their respective owners.