Deploying Ruby on Rails on Ubuntu Feisty Fawn via Mongrel Cluster and Apache

Note:

  • A quick, down and dirty solution. There are more verbose resources on how to setup Mongrel Cluster and Apache. But this is also specifically tailored for Ubuntu Feisty Fawn.
  • After installing mongrel, when executing ./script/server, you will not use Webrick anymore, but instead mongrel for development. You can still use Webrick if you want, but there isn’t much of a difference.

Plan of Attack

  • Install, configure, and test Mongrel Cluster
  • Install and test Apache
  • Start Mongrel Cluster on boot

Installing Mongrel Cluster

sudo apt-get install ruby1.8-dev
sudo gem install -y mongrel mongrel_cluster

Note: If you see the following make sure you select the latest version of mongrel for ruby. In this case option 2.

Select which gem to install for your platform (i486-linux)
 1. mongrel 1.0.1 (mswin32)
 2. mongrel 1.0.1 (ruby)
 3. mongrel 1.0 (mswin32)
 4. mongrel 1.0 (ruby)
 5. Skip this gem
 6. Cancel installation
> 

Configuring Mongrel Cluster

Go to your Rails application directory and execute:

mongrel_rails cluster::configure -p 8000 -n 3

This allows mongrel to spawn 3 instance to handle the load. Each instance will open on port 8000, and succeeding. So that is 8000, 8001, and 8002.

Note: The mongrel_rails command has alot of options. Executing mongrel_rails -h will get you more information. All of these options can be changed later.

This will create the a mongrel_cluster configuration file in RAILS_ROOT/config/mongrel_cluster.yml File

Testing Mongrel Cluster

In your Rails application directory, execute:

mongrel_rails cluster::start

Now open up http://localhost:8000/, http://localhost:8001/, and http://localhost:8002/ to ensure that your site is working perfectly fine.

Installing Apache

Enter into the Terminal:

sudo apt-get install apache2
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http
sudo a2enmod rewrite

We will now create a common rails configuration file. As root open up /etc/apache2/mods-available/rails.conf File, and insert the following:

  ServerName railsapp.com
  DocumentRoot /var/www/railsapp.com/public

  <Directory "/var/www/railsapp.com/public">
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
  </Directory>

  RewriteEngine On

  # Uncomment for rewrite debugging
  #RewriteLog logs/railsappapp_rewrite_log
  #RewriteLogLevel 9 

  # Check for maintenance file and redirect all requests
  #  ( this is for use with Capistrano's disable_web task )
  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
  RewriteCond %{SCRIPT_FILENAME} !maintenance.html
  RewriteRule ^.*$ /system/maintenance.html [L]

  # Rewrite index to check for static
  RewriteRule ^/$ /index.html [QSA] 

  # Rewrite to check for Rails cached page
  RewriteRule ^([^.]+)$ $1.html [QSA]

  # Redirect all non-static requests to cluster
  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
  RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]

  # Deflate
  AddOutputFilterByType DEFLATE text/html text/plain text/css
  # ... text/xml application/xml application/xhtml+xml text/javascript
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4.0[678] no-gzip
  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

  # Uncomment for deflate debugging
  #DeflateFilterNote Input input_info
  #DeflateFilterNote Output output_info
  #DeflateFilterNote Ratio ratio_info
  #LogFormat '"%r" %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate
  #CustomLog logs/myapp_deflate_log deflate

Now we’ll set up the virtual host for our site railsapp.com For the last time as root open up /etc/apache2/sites-available/railsapp File and insert the following:

Listen 8080
<VirtualHost *:8080>
  <Location />
    SetHandler balancer-manager
    Deny from all
    Allow from localhost
  </Location>
</VirtualHost>

<Proxy balancer://mongrel_cluster>
  BalancerMember http://127.0.0.1:8000
  BalancerMember http://127.0.0.1:8001
  BalancerMember http://127.0.0.1:8002
</Proxy>

<VirtualHost *:80>
  Include /etc/apache2/mods-available/rails.conf
  ErrorLog /var/log/apache2/rails_errors_log
  CustomLog /var/log/apache2/rails combined
</VirtualHost>

The first VirtualHost enables a front end for load balancing, available only to localhost on port 7999.
The second VirtualHost is our rails application. Notice how it is pulling in our default configuration (/etc/apache2/mods-available/rails.conf File). If you want to make changes you can specify it here. Need to specify a ServerName directive? Put it in here.

Lets enable the virtual host

sudo a2ensite railsapp

and restart Apache.

sudo /etc/init.d/apache2 restart

Now pull up your the domain you entered and your Rails application should load!

Note: If you can’t seem to access your site, its because the default virtual host has a higher precedence. Execute sudo a2dissite default Terminal. Similarly ensure that you are access your site via the domain you specified in the ServerName directive. In this case railsapp.com

If everything is work, you are on your way to more production based hosting solution.

Start Mongrel Cluster on Boot

Create mongrel_cluster conf directory (/etc/mongrel_cluster).

sudo mkdir /etc/mongrel_cluster

In the Mongrel Cluster gem, there is an init.d script you need to copy.

sudo cp /usr/lib/ruby/gems/1.8/gems/mongrel_cluster-0.2.1/resources/mongrel_cluster/mongrel_cluster /etc/init.d

Now let’s make the script executable.

sudo chmod +x /etc/init.d/mongrel_cluster

Now we need to add th init.d script to startup.
On Ubuntu:

sudo update-rc.d mongrel_cluster defaults

On RHEL/CentOS:

/sbin/chkconfig --level 345 mongrel_cluster on

Now create a symbolic link from RAILS_ROOT/config/mongrel_cluster.yml to a file in /etc/mongrel_cluster:

sudo ln -s /path/to/railsapp/config/mongrel_cluster.yml /etc/mongrel_cluster/railsapp

There you have it, you should be good to go!

Comments, bugs, problems, improvements

Have any bug, or problem? Leave a comment please.

18 Comments »

  1. chfl4gs_ said,

    May 21, 2007 @ 3:01 am

    Got a write-up on combination RoR + mongrel_cluster + apache and RoR + mongrel_cluster + pound. It seems the later combination is less resource hungry while the former is more flexible due to powerful rewrite module of apache httpd. Stripping down apache httpd helps by removing unused modules and lesser file descriptor writing.

  2. aizatto said,

    May 21, 2007 @ 12:43 pm

    Thanks for the advice :)

  3. derek said,

    May 26, 2007 @ 6:55 pm

    i spent a few hours trying to get it to work and failed

    i have to say that is bad compared to a lamp install!

  4. aizatto said,

    May 26, 2007 @ 8:31 pm

    Hi derek,

    Yes I’ll admit that getting srails working is harder than getting php un and running

    contact me privately regarding your rails problems, and maybe we can sort it :).

    Regards,
    Aizat

  5. locusf said,

    May 27, 2007 @ 5:00 am

    Hi!

    I have a problem with accessing a certain command (ie. http://localhost/controller/action), this gives me a 403 Forbidden. I have done everything like you have shown on this tutorial.

    PS. How do I deploy my app since I don’t have wepapp/current/public ?

    Regards,
    LoCusF

  6. aizatto said,

    May 27, 2007 @ 7:34 am

    Hi locuscf!

    Thanks for noticing the error (wrt to the current/public) That’s off my capistrano setup, I must have forgotten to remove it. just make it webapp/public.

    The other fault is that I forgot to include enable other apache module:

    sudo a2enmod proxy_http

    Hope this helps

    Regards,
    Aizat

  7. locusf said,

    May 27, 2007 @ 2:50 pm

    Hey!

    The proxy_http fixed the 403, thanks!

    Regards,
    LoCusF

  8. caene.us » Blog Archive » Rails on feisty on slicehost said,

    June 17, 2007 @ 12:08 am

    […]  http://rails.aizatto.com/2007/05/20/deploying-ruby-on-rails-on-ubuntu-feisty-fawn-via-mongrel-clus… […]

  9. Alan harper said,

    June 21, 2007 @ 3:58 am

    Very handy. Only extra item I needed was to make sure the link in /etc/mongrel_cluster finished in .yml

  10. peter retief said,

    July 2, 2007 @ 3:41 pm

    I did the “Start Mongrel Cluster on Boot” a bit different - see link

  11. peter retief said,

    July 2, 2007 @ 3:44 pm

    I did the “Start Mongrel Cluster on Boot” a bit different - see link

    http://pieter-mantis.blogspot.com/2007/07/start-mongrel-cluster-on-boot-ubuntu.html

  12. addame said,

    July 16, 2007 @ 4:07 am

    Hi!
    Thanks a lot for this very instructive tutorial ! it helps me to get my small application up !

    The only problem is when I tried to lunch mongrel_cluster, where I have problem.
    In fact the mongrel_rails start -e production is working fine. However mongrel_rails cluster::start is not working. The log I get the following output :

    starting port 8000
    starting port 8001
    starting port 8002

    But when I lunched the browser to the application url and port 8000 for
    example, the mongrels seems not working.

    I looked at the log file and get for the first mongrel instance :

    ** Daemonized, any open files are closed. Look at tmp/mongrel.8000.pid
    and log/mongrel.8000.log for info.
    ** Starting Mongrel listening at 0.0.0.0:8000
    ** Changing group to mongrel.
    ** Changing user to mongrel.
    ** Starting Rails with production environment…
    ** Mounting Rails at /home/rails/projects/myapps…
    /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:30:in
    `gem_original_require’: no such file to load –
    /home/rails/projects/jokes/config/environment (LoadError)
    from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:30:in
    `require’
    from
    /usr/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/rails.rb:157:in
    `rails’
    from
    /usr/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails:116:in
    `cloaker_’
    from
    /usr/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/configurator.rb:138:in
    `call’
    from
    /usr/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/configurator.rb:138:in
    `listener’
    from
    /usr/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails:98:in
    `cloaker_’
    from
    /usr/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/configurator.rb:51:in
    `call’
    from
    /usr/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/configurator.rb:51:in
    `initialize’
    from
    /usr/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails:83:in `new’
    from
    /usr/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails:83:in `run’
    from
    /usr/lib/ruby/gems/1.8/gems/mongrel-1.0.1/lib/mongrel/command.rb:211:in
    `run’
    from /usr/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails:248
    from /usr/bin/mongrel_rails:16:in `load’
    from /usr/bin/mongrel_rails:16

    It’s the same thing for the two other instances.

    My mongrel cluster configuration is as follows :

    user: mongrel
    group: mongrel
    cwd: /home/rails/projects/myapps
    log_file: log/mongrel.log
    port: “8000″
    environment: production
    address: 127.0.0.1
    pid_file: tmp/mongrel.pid
    servers: 3

    Do you have any idea of this problem ?

    Thanks in advance !!

    Addam

  13. Brad said,

    August 16, 2007 @ 1:49 am

    When I start my cluster as you describe, I only get responses on ports 8000 and 8001, not 8002 for some reason.

  14. Brad said,

    August 16, 2007 @ 1:54 am

    I figured it out: there is a typo in this command:

    mongrel_rails cluster::configure -p 8000 -n 3

    The -n option is case sensitive. Use -N to set the number of servers. -n sets number of threads.

  15. Jereme said,

    September 12, 2007 @ 8:03 am

    I’m running into a problem with the Apache2 setup. Every time I try and access the site I receive a “404 Not Found” page. I’m guessing the rewrite rules are not in effect, but have no clue how to make them work properly.

    Any help is much appreciated!

  16. alfredo said,

    October 10, 2007 @ 4:26 am

    A word of note: Ruby 1.8.5 doesnt work with mongrel_cluster 1.0.2

    you need to install manually (not apt-get) the 1.8.6 version

  17. Ani said,

    January 15, 2008 @ 9:50 pm

    Ok i’ve got a noobish question (if anybody still visits this place)

    What if I want to run multiple application with load-balancer. How can I make a seperate entry for a new application and make sure it gets a new load-balancer so it doesnt end up proxy-ing it to an other application.

  18. Remington D. said,

    February 26, 2008 @ 1:16 pm

    I’m sorry, you seem to have mistaken me for someone who cares.

RSS feed for comments on this post · TrackBack URI

Leave a Comment