Best practice for setting up RVM, Passenger/Apache with multiple Rubies and running as specific users

apache-2.2phusion-passengerrubyrvmubuntu-10.04

My goal is to run ruby applications under different server users with potentially different versions of ruby.

So i would have users that serve as the "hosting account" essentially. Document root/application files will live in their home directory along with ruby version(s) and gemsets managed with RVM. A user will have one or more web apps it needs to run. The virtual hosts for this user's site will point to the document root in the users home dir and webserver will also effectively run as this user:group.

Example layout:

/home/theuser
  /.rvm
  /applications
     /railsapp1
       /public
       [ other rails dirs ]
     /somephpapp (symfony, zf, etc.)
       /public
       [ other framework dirs ]
  /www
    /railsapp1.com (ln -s ../applications/railsapp1/public)
    /somestaticsite.com
    /somephpapp.com (ln -s ../applications/somephpapp/public)

So…

Question 1: I this even possible? I know passenger supports ruby versions and passenger users (i assume the passenger user equiv to specifying the user:group for fcgi, php-fpm, SuExec) at the virtual host level but all the intstuctions im finding seem to install the apache module from a specific RVM user, that seems odd. Or is it just a matter of creating a generic user to install the module from and then doing everything else on a per account basis?

Question 2: Even if this is possible is the correct way to set things up? Whats the best practice here given that:

  1. The webserver/application MUST run as a given account's user:group
  2. MUST have the ability to run different version of ruby on per application basis
  3. Each user MUST be able to run multiple applications
  4. Each application MUST be contained under a specific user's home dir
  5. The user MUST be sandboxed to his/her homedir (not a sodoer)

(Note: I myself am not a ruby dev/user aside from the odd shell script here or there or using compass/zurb-foundation so Im open to options other than Passenger. Also this server is not intended as a production environment.)

Best Answer

When I initially posted this i was trying to save the time of going down this path for the setup only to have it not work. After a couple days I just gave it a shot and it worked. What i did was:

Create a user to actually install passenger from. I suspect you could use root for this but i created a standalone admin level user called passenger. I also disabled all remote access for this user.

sudo useradd -m -s /bin/bash passenger

Switch to the new passenger user and install rvm and use it to install my preferred default ruby (1.9.3-stable):

su - passenger
curl -L https://get.rvm.io | bash
rvm install 1.9.3

Install passenger and the apache module:

gem install passenger
passenger-install-apache2-module

Add the passenger mod files to /etc/apache2/mods-available... The .load file:

# /etc/apache2/mods-available/passenger.load
LoadModule passenger_module /home/passenger/.rvm/gems/ruby-1.9.3-p429/gems/passenger-4.0.5/libout/apache2/mod_passenger.so

The .conf file:

# /etc/apache2/mods-available/passenger.conf

PassengerRoot /home/passenger/.rvm/gems/ruby-1.9.3-p429/gems/passenger-4.0.5
PassengerDefaultRuby /home/passenger/.rvm/wrappers/ruby-1.9.3-p429/ruby
PassengerUserSwitching on
PassengerDefaultUser www-data
PassengerDefaultGroup www-data

# Any other global-only configuration

Then i enabled the module and ran a config test, followed by a reload if successful

sudo a2enmod passenger
sudo apache2ctl configtest
sudo service apache2 graceful # if Syntax Ok from previous command

After this I configured my virtual host as needed... example:

<VirtualHost *:80>
    ServerName appname.yourdomain.com
    ServerAdmin appuser@yourdomain.com
    DocumentRoot /home/appuser/path/to/doc/root

    PassengerSpawnMethod smart
    PassengerPoolIdleTime 300
    PassengerMaxRequests 500
    PassengerStatThrottleRate 5
    PassengerMinInstances 2
    PassengerRuby /home/appuser/.rvm/rubies/ruby-1.9.3-p429/bin/ruby

    <Directory "/home/appuser/path/to/doc/root">
        Options Indexes -ExecCGI FollowSymLinks -MultiViews
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>

Since PassengerUserSwitching is on and the PassengerRuby is owned by a different user, passenger will automatically run the application as this user:group. However, there are specific passenger directives you can use to set user and group at the vhost level. Whether or not those need to match the owner of the PassengerRuby i do not know for sure.

Articles/Docs that helped:

  1. Multiple Rubies with a single Passenger
  2. How To Install Redmine on Ubuntu 11.10 Server using Apache and mod_passenger with performance improving options (Used mainly to help configure performance type settings)
  3. Phusion Passenger Configuration Reference (Apache)
Related Topic