Ruby on Rails - Deployment

June, 2011

I am in the middle of converting my rails applications from rails 2 to rails 3, and have made the unhappy discovery that my old deployment solution of apache and mongrel clusters is no longer "in vogue" for rails 3 (i.e. it don't work!).

As a curious aside, Zed Shaw, the developer of mongrel went non-linear in a big time anti-rails way back in 2008, writing a now infamous essay "Rails is a Ghetto". The general opinion is that he sabotaged his own credibility by generous use of profanity and vicious language. He may have some valid points about rails, but not too many people are listening. He complains that he has trouble finding employment, I think that anyone who reads what he writes can guess why.

Anyway, all this aside, I find compelling reasons to abandon mongrel in favor of passenger regardless.

If Apache virtual hosts give me any more headaches, I just might jump to working with Nginx.

Two solutions seem to be popular.

Unicorn

The Nginx web server (pronouned "Engine-X") is endorsed by people in the know (although I have been down this road with lighttpd, which ultimately dead ended). Unicorn along with nginx is a recommended solution for high traffic web sites (thousands of hits per second), and is currently (or by the time you read this, was at one time) used to host the Twitter website. The word is that nginx is much faster (execution times) and much easier to configure than apache. That latter claim would be a slam dunk for any reasonable web server design.

As one person says, "almost anything is faster and more stable than apache under load".

The claim is that nginx and unicorn are designed to use unix kernel facilities for scheduling, not an application managed queue like mongrel.

Passenger

Also known as mod_rails or mod_rack. The claim is that it "makes deployment of rails applications a breeze", well that sounds great, but we will see. Passenger is recommended as a nice solution for low traffic rails sites (and that is certainly me at this point in time). Also since I am currently running apache, I would be pleased to have a ruby deployment solution that did not involve switching web servers.

You can buy a commercial (yet open source) version known as Phusion Passenger, but of course I am not going that route. What I do is:

gem install passenger
This fetches daemon_controller-0.2.5 and passenger-3.0.7 for me. After this, I run the install script:
passenger-install-apache2-module
This discovers that some apache packages are missing, namely the apache headers (no doubt I need apache-devel) and the APR (apache portable runtime) headers and the APU (apache portable runtime utility headers.

I do yum install httpd-devel and it pulls in the other two also as dependencies (along with some other things.

apr-devel-1.4.5-1.fc15.x86_64
db4-cxx-4.8.30-3.fc15.x86_64
db4-devel-4.8.30-3.fc15.x86_64
apr-util-devel-1.3.12-1.fc15.x86_64
httpd-devel-2.2.17-10.fc15.1.x86_64
After getting these packages, we once again do:
passenger-install-apache2-module

Now it is busy compiling lots of stuff. It instructs me to add these 3 lines to my apache configuration file.

LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-3.0.7/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-3.0.7
PassengerRuby /usr/bin/ruby
What I do is to put these lines into /etc/httpd/conf.d/passenger.conf

Once I have done this, they claim I can set up a virtual host as follows. If the rails application is in /u1/rails/myapp, do this:

<virtualhost * >
ServerName www.myapp.com
DocumentRoot /u1/rails/myapp/public
RailsEnv development
<Directory /u1/rails/myapp/public>
  AllowOverride all
  Options -MultiViews
</Directory>
</virtualhost>
I put these lines into /etc/httpd/conf.d/myapp.conf After I do service httpd restart I am in business!

I do have some apache configuration issue to sort out for my main host, because everything on the main host is getting redirected to passenger, which is trying to do rails routing on all of my static content, but displaying the message:

Routing Error
No route matches "/extra"

For further information, they recommend the following:


Feedback? Questions? Drop me a line!

Ruby on Rails notes / tom@mmto.org