RubyOnRails + FastCGI in OpenBSD 4.0 Apache-chroot

If you've ever moved anything into chroot before, then you probably feel confident that you could get Rails done in a couple of minutes. I thought I could, and I was wrong! However, after much head scratching, Googling, and poring over the same log files about a thousand times I have succeeded. The good news is that if you know the steps then you can make it all work in just a few minutes after all.

  1. Install stuff
    # pkg_add ruby ruby-gems ruby-rails mod_fastcgi fcgi
    # gem install fcgi
    
    Almost everything you need is available as a package! However, you will need to install the fcgi Ruby Gem yourself.
  2. Move tons of stuff into chroot
    # export CHROOT=/var/www
    # cp -p /bin/sh ${CHROOT}/bin
    # cp -p /sbin/ldconfig ${CHROOT}/sbin
    # cd /usr/lib
    # cp -p libc.so.39.3 libcrypto.so.13.0 libm.so.2.3 libncurses.so.10.0 libreadline.so.3.0 libssl.so.11.0 libz.so.4.1 ${CHROOT}/usr/lib
    # cd /usr/local/lib
    # cp -p libfcgi.so.0.0 libruby.so.1.84 ${CHROOT}/usr/lib
    # cp -rp ruby ${CHROOT}/usr/lib
    # cp -p /usr/local/bin/ruby ${CHROOT}/usr/local/bin
    
    This may take a while, and will take some space. Make sure you get everything, because Rails will give your cryptic errors if something is missing, such as “uninitialized constant RailsFoo (NameError)”.
  3. Run ldconfig in chroot
    # export CHROOT=/var/www
    # mkdir -p ${CHROOT}/var/run
    # chroot ${CHROOT} /sbin/ldconfig /usr/local/lib
    
    This builds ld.so.hints in your chroot. If you don't do this then libs in /var/www/usr/local/lib won't be found. An alternative is to put everything in /var/www/usr/lib, but I prefer to have the chroot mirror the original.
  4. Create a new rails skeleton:
    # rails /var/www/path/to/rails
    
  5. Modify /var/www/conf/httpd.conf
    LoadModule fastcgi_module	/usr/lib/apache/modules/mod_fastcgi.so
    
    <VirtualHost *:80>
        ServerName my.server.name
        DocumentRoot /path/to/rails/public
        ErrorLog /path/to/rails/logs/error_log
        CustomLog /path/to/rails/logs/access_log combined
        <Directory /rails>
            Options ExecCGI FollowSymLinks
            AllowOverride all
            Allow from all
            Order allow,deny
        </Directory>
    </VirtualHost>
    
    Obviously replace /path/to/rails with something more appropriate, and tailor the options to your liking.
  6. Check your config & restart httpd
    # apachectl configtest
    # apachectl stop
    # apachectl start
    
  7. Fire up the browser! At this point it should be working!
  8. What if it's NOT working?!

    Check the httpd logs, both the VirtualHost and the main server logs. Try running outside chroot to see if chroot is the problem or if it's something else. Chroot in and run it by hand:

    # chroot /var/www sh
    # ruby /path/to/rails/public/dispatch.fcgi
    
    If Ruby dumps on you then something is wrong. If you get a status 500 server error then (believe it or not) everything is fine, but you have an error in httpd.conf.

    If you're getting errors like uninitialized contact RailsFCGIHandler (NameError) then either Ruby is failing to find the files or you're missing a *.so file. If you install a package or gem later, then move it into chroot you may not get everything that changed. In my case, Ruby wasn't updating LOAD_PATH because I'd forgotten a few things in places I didn't expect. Check with something like find /usr/local/lib/ruby -ctime 1...

Corrections and suggestions are welcome!

Mysql GEM

Any information about mysql? I have mysql.sock in my chroot and it works with PHP but I get Mysql GEM errors when running my rails application.

Re: Mysql GEM

Never mind, I just needed to cp /usr/local/lib/libmysqlclient.so.16.0 /var/www/usr/local/lib/

Minor modification

Thank's for this article.
Some little modification I have had to do :

# export CHROOT=/var/www

#mkdir ${CHROOT}/bin ${CHROOT}/sbin ${CHROOT}/usr ${CHROOT}/usr/lib
I added a leading / at the end of the destination directory

# cp -p /bin/sh ${CHROOT}/bin/
# cp -p /sbin/ldconfig ${CHROOT}/sbin/
# cd /usr/lib
# cp -p libc.so.39.3 libcrypto.so.13.0 libm.so.2.3 libncurses.so.10.0 libreadline.so.3.0 libssl.so.11.0 libz.so.4.1 ${CHROOT}/usr/lib/

# cd /usr/local/lib
#mkdir ${CHROOT}/usr/local ${CHROOT}/usr/local/lib ${CHROOT}/usr/local/bin
# cp -p libfcgi.so.0.0 libruby.so.1.84 ${CHROOT}/usr/local/lib/
# cp -rp ruby ${CHROOT}/usr/local/lib/

# cp -p /usr/local/bin/ruby ${CHROOT}/usr/local/bin/

#mkdir ${CHROOT}/usr/libexec
#cp -p /usr/libexec/ld.so ${CHROOT}/usr/libexec/

add in httpd.conf

LoadModule rewrite_module /usr/lib/apache/modules/mod_rewrite.so

ServerName my.server.name
DocumentRoot /path/to/rails/public
ErrorLog /path/to/rails/log/error_log
CustomLog /path/to/rails/log/access_log combined

Options ExecCGI FollowSymLinks
AllowOverride all
Allow from all
Order allow,deny

Regards

Thanks for the mods!

Thanks for the mods!

Looks like I missed some things that I had already done prior to the Rails install, which shows the benefit of testing on a clean box.