Apache, Passenger, and the environment

This is a quick note on building an Apache+Passenger+Ruby 2.4 environment on RHEL7, with an explanation of some odd path issues with libraries and how to resolve them for both regular users and system users.

We’re building a RedHat Enterprise (RHEL) 7 server with Ruby 2.4. We use Passenger to route traffic from Apache to the rails applications hosted on the box. RHEL7, by default, ships with Ruby 2.0.0-p684, which is outdated. To get up to Ruby 2.4, we have to add the software collections repository and then make a few configuration changes.

We start by installing a few packages. I found that we needed three base Ruby packages, plus Passenger:

1
yum install rh-ruby24 rh-ruby24-rubygem-bundler rh-ruby24-ruby-devel mod_passenger

You can get into a bad place if you don’t install the Ruby 2.4 version of the Bundler, because RHEL will fall back on the Ruby 2.0.0-p684 version. The development libraries are needed for building native gems on deployment. We do not uninstall Ruby 2.0.0-p684 as part of this process because RHEL’s puppet environment depends on it.

First, users who have shell on the box need Ruby 2.4 in their path. The repository ships with a shell script,  /opt/rh/rh-ruby24/enable, which you can add to the default user profile. Let’s look under the hood at that script:

1
2
3
4
5
export PATH=/opt/rh/rh-ruby24/root/usr/local/bin:/opt/rh/rh-ruby24/root/usr/bin${PATH:+:${PATH}}
export LD\_LIBRARY\_PATH=/opt/rh/rh-ruby24/root/usr/local/lib64:/opt/rh/rh-ruby24/root/usr/lib64${LD\_LIBRARY\_PATH:+:${LD\_LIBRARY\_PATH}}
export MANPATH=/opt/rh/rh-ruby24/root/usr/local/share/man:/opt/rh/rh-ruby24/root/usr/share/man:$MANPATH
export PKG\_CONFIG\_PATH=/opt/rh/rh-ruby24/root/usr/local/lib64/pkgconfig:/opt/rh/rh-ruby24/root/usr/lib64/pkgconfig${PKG\_CONFIG\_PATH:+:${PKG\_CONFIG\_PATH}}
export XDG\_DATA\_DIRS=/opt/rh/rh-ruby24/root/usr/local/share:/opt/rh/rh-ruby24/root/usr/share:${XDG\_DATA\_DIRS:-/usr/local/share:/usr/share}

SCL paths really roll right off the tongue, don’t they? Anyway, it gets the job done and anyone with a shell has Ruby 2.4 as their default instead of Ruby 2.0.0-p684.

The next step is to let Passenger know that it’s using Ruby 2.4 instead of Ruby 2.0.0-p684. This was our original configuration in /etc/httpd/conf.d/passenger.conf:

1
2
3
PassengerRoot /usr/share/ruby/vendor\_ruby/phusion\_passenger/locations.ini
PassengerRuby /opt/rh/rh-ruby24/root/usr/bin/ruby
PassengerInstanceRegistryDir /var/run/passenger-instreg

We tried deploying with this configuration and the application exploded, refusing to run. This was the error message:

1
/opt/rh/rh-ruby24/root/usr/bin/ruby: error while loading shared libraries: libruby.so.2.4: cannot open shared object file: No such file or directory

I went down some odd rabbit holes on the internet looking for a solution to this, but it wound up being straightforward. The Apache user doesn’t have a shell, which means it doesn’t know anything about all those special paths. Most of them aren’t relevant, but LD_LIBRARY_PATH is the kicker. We have to set it in two places. First, we add it to /etc/sysconfig/httpd, so that Apache knows itself knows about it:

1
LD_LIBRARY_PATH=/opt/rh/rh-ruby24/root/usr/local/lib64:/opt/rh/rh-ruby24/root/usr/lib64

The syntax here matters; I lost a lot of time trying to mimic a standard export command and coming to grief. The second place you have to add it is the Passenger configuration, so that the application knows about the paths. I missed this step initially, and watched with disbelief as the shared libraries error moved from the Apache error logs to the Passenger error logs. Here’s the revised Passenger configuration, using’s Apache’s PassEnv directive:

1
2
3
4
PassengerRoot /usr/share/ruby/vendor\_ruby/phusion\_passenger/locations.ini
PassengerRuby /opt/rh/rh-ruby24/root/usr/bin/ruby
PassengerInstanceRegistryDir /var/run/passenger-instreg
PassEnv LD_LIBRARY_PATH

After that change I bounced Apache again and was back in business.