Westhost on Rails

By Aaron Gustafson

The Requisite Disclaimer: If you are on a different hosting company, I cannot guarantee this tutorial will work for you (though it may be helpful in figuring out your issues). As always, before you make changes to critical files (http.conf, .bashrc, etc.), do yourself a favor and make a backup copy; this tutorial offers assistance, but no warranty, so if you mess something up during the install, you’re on your own (but Westhost tech support should be helpful). Finally, this tutorial assumes some familiarity with the Site Manager from Westhost and some basic knowledge of the Linux shell.

Now that I’ve had to muddle through it a few times, I decided that, for my own sanity and to aid anyone else out there who may be going through the same thing, I would put together a comprehensive tutorial on how to install Ruby on Rails at Westhost. The major problems that arise and could trip you up are

  1. Westhost runs Apache 1.3,
  2. FastCGI is not installed (and Rails will run incredibly slow without it), and
  3. you cannot install applications in /usr/bin.

This tutorial will get you up and running with a very simple Rails page on your Westhost VPS server using Apache 1.3 with FastCGI. For simplicity’s sake, I am going to set up the test Rails app on its own hostname (demo.yoursitehere.com).

Required Site Applications

Before we get started, log into your Site Manager (it can be found at http://www.yoursitehere.com/manager) and make sure the following are installed:

While you’re there, under Domain Management, set up a new hostname for your domain using the following values:

Now SSH into your site and we can get started.

Step 1: Collect & unpack

First of all, make sure you are in your home directory

[~]$ cd /home/your_username

and then we can start the downloading and unpacking. First we get Ruby (the latest is 1.8.3 as of this writing)

[~]$ wget http://rubyforge.org/frs/download.php/6155/ruby-1.8.3.tar.gz
[~]$ tar -xvzf ruby-1.8.3.tar.gz
[~]$ rm -f ruby-1.8.3.tar.gz

Next up is the latest Ruby Gem Manager (version 0.8.11 at present)

[~]$ wget http://rubyforge.org/frs/download.php/5207/rubygems-0.8.11.tgz
[~]$ tar -xvzf rubygems-0.8.11.tgz
[~]$ rm -f rubygems-0.8.11.tgz

then the latest FastCGI Developer’s Kit (version 2.4.0 at present)

[~]$ wget http://www.fastcgi.com/dist/fcgi-2.4.0.tar.gz
[~]$ tar -xvzf fcgi-2.4.0.tar.gz
[~]$ rm -f fcgi-2.4.0.tar.gz

and, finally, the FastCGI module for Apache (version 2.4.2 at present)

[~]$ wget http://www.fastcgi.com/dist/mod_fastcgi-2.4.2.tar.gz
[~]$ tar -xvzf mod_fastcgi-2.4.2.tar.gz
[~]$ rm -f mod_fascgi-2.4.2.tar.gz

Step 2: Configure & Install Ruby

Starting in your home directory, get into the Ruby folder

[~]$ cd ruby-1.8.3
We need to configure the source before we compile, letting it know that Ruby will be installed in /usr/local/ruby instead of /usr/local:

[ruby-1.8.3]$ ./configure --prefix=/usr/local/ruby

Then go ahead and create the makefile and install Ruby.

[ruby-1.8.3]$ make && make install

As we will be working with Ruby from the command line, we need it as part of our PATH, which means editing our .bashrc file:

[ruby-1.8.3]$ pico /.bashrc

looking a few lines down from the top, you will see this line

export PATH="$PATH:/usr/local/apache/bin"

Change it to read

export PATH="$PATH:/usr/local/apache/bin:/usr/local/ruby/bin"

and save as you exit. Make sure your current session is using the new .bashrc file and then check your Ruby version (which will tell us if Ruby is working):

[ruby-1.8.3]$ source /.bashrc
[ruby-1.8.3]$ ruby -v
ruby 1.8.3 (2005-9-21) [i686-linux]

Return to your home directory

[ruby-1.8.3]$ cd ..

Step 3: Installing Ruby Gem Manager

We will be using the Ruby Gem Manager to install pretty much every other Ruby or Rails component we need, so it is next on our list. First of all, enter its folder

[~]$ cd rubygems-0.8.11

and then install it using Ruby

[rubygems-0.8.11]$ ruby setup.rb

So now we have the Gem Manager installed, but you’ll notice that typing gem at the prompt gives you an error that the system doesn’t know which interpreter to use for gem. We need to fix the gem bang line:

[rubygems-0.8.11]$ pico /usr/local/ruby/bin/gem

Change the first line to read

#!/usr/local/ruby/bin/ruby

Save your work when you exit and give gem a test run

[rubygems-0.8.11]$ gem list

We don’t have any gems installed yet, but that’s what we’re doing next.

Step 4: Install Rails

Now that we have the Gem Manager installed, the rest of the basic stuff is a snap. To install Rails, simply type the following

[rubygems-0.8.11]$ gem install rails --include-dependencies

This could take a little while, but should complete within a few minutes. In that short time, you can decide on the type of markup shorthand you’d like to work with (if any). Textile is a pretty popular one, but Markdown has its fans too. You could always go for both, but that seems a tad gluttonous.

If you want Textile, enter the following:

[rubygems-0.8.11]$ gem install RedCloth

If you want Markdown enter the following:

[rubygems-0.8.11]$ gem install BlueCloth

That was easy, but we’re not out of the woods yet. Unfortunately for us, Ruby 1.8.3 and the latest Rails (0.9.2 at present) do not see eye to eye on a certain format, but that’s okay, there’s an easy fix. In Ruby 1.8.3, “Format” is not defined, so we need to fix ActiveSupport’s clean_logger.rb. Traverse the system to get to the file (this can be done in a single command, but I broke it up for legibility):

[rubygems-0.8.11]$ cd /usr/local/ruby/lib/ruby/gems/1.8/gems/
[gems]$ activesupport-1.1.1/lib/active_support/
[active_support]$ pico clean_logger.rb

Toward the bottom of this file, you will see the following

  private
    remove_const "Format"
    Format = "%s\n"
    def format_message(severity, timestamp, msg, progname)
      Format % [msg]
    end

As “Format” is not defined, we need to test for it before removing. To do this, change that section to read

  private
    if const_defined?(:Format) # Not defined in Ruby 1.8.3
      remove_const "Format"
    end
    Format = "%s\n"
    def format_message(severity, timestamp, msg, progname)
      Format % [msg]
    end

Now that we’ve done that, we can test our Rails install:

[active_support]$ cd /var/www
[www]$ rails demo
[www]$ cd demo
[demo]$ ruby script/server

Open web browser to http://www.yoursitehere.com:3000/ and look what you did. Congratulations, you’ve put Ruby on Rails!

Step 5: Getting FastCGI up on Apache 1.3

OK, all of that stuff was pretty easy, but know things get just a little more complex. If you don’t want to run Rails through Apache (and there are plenty of reasons not to), feel free to stop now, but if you would like Rails to run like the rest of your sites, keep reading, but be warned that it gets very tedious from here on in.

First off, return to your home directory:

[demo]$ cd /home/your_username

We need to install the FastCGI Dev Kit. To do that, enter its directory, configure and install it similarly to how we did Ruby:

[~]$ cd fcgi-2.4.0
[fcgi-2.4.0]$ ./configure --prefix=/usr/local/fcgi
[fcgi-2.4.0]$ make && make install

Next on the agenda is getting Apache to understand FastCGI. To do this, we need to compile and install the DSO for Apache, which uses a slightly different process:

[fcgi-2.4.0]$ cd ..
[~]$ cd mod_fastcgi-2.4.2
[mod_fastcgi-2.4.2]$ apxs -o mod_fastcgi.so -c *.c
[mod_fastcgi-2.4.2]$ apxs -i -a -n fastcgi mod_fastcgi.so

That put FastCGI in Apache’s httpd.conf file, but it’s likely going to be in the wrong place, so we’ll need to edit it.

[mod_fastcgi-2.4.2]$ pico /etc/httpd/conf/httpd.conf

Most likely the install placed the LoadModule for FastCGI inside the HAVE_FRONTPAGE_SPHERA block:

<IfDefine HAVE_FRONTPAGE_SPHERA>
  LoadModule frontpage_module  modules/mod_frontpage_sphera.so
  LoadModule fastcgi_module    /usr/lib/apache/mod_fastcgi.so
</IfDefine>

We need to change that to read

<IfDefine HAVE_FRONTPAGE_SPHERA>
  LoadModule frontpage_module  modules/mod_frontpage_sphera.so
</IfDefine>
LoadModule fastcgi_module   /usr/lib/apache/mod_fastcgi.so

A little further down, we need to do the same to the AddModule statement:

<IfDefine HAVE_FRONTPAGE_SPHERA>
  AddModule mod_frontpage_sphera.c
  AddModule mod_fastcgi.c
</IfDefine>
becomes
<IfDefine HAVE_FRONTPAGE_SPHERA>
  AddModule mod_frontpage_sphera.c
</IfDefine>
AddModule mod_fastcgi.c

We then need to add the handler for FastCGI, so scroll down until you see some other AddHandler statements (or run a search) and insert the following:

AddHandler fastcgi-script fcg fcgi fpl

Finally, create an instance of our demo app near the bottom of the httpd.conf file:

# FastCGI
<IfModule mod_fastcgi.c>
  FastCgiIpcDir /tmp/fcgi_ipc
  FastCgiServer /var/www/demo/public/dispatch.fcgi
  [continues from previous line] -initial-env RAILS_ENV=development -processes 1 -idle-timeout 60
  #FastCgiServer /var/www/demo/public/dispatch.fcgi
  [continues from previous line] -initial-env RAILS_ENV=production -processes 1 -idle-timeout 60
</IfModule>

<VirtualHost *>

You’ll notice I have a commented line for the production environment, when the site is ready to go out of development and into production, you just comment out the first line and uncomment the second line and you are good to go. Note: I do not recommend developing and deploying on the same box.

Processes: Why only one process? Well, 1 is usually enough for most applications. If you are getting really heavy traffic, you could bump it up to 2, but FastCGI can be a bit resource hungry. It is even worse if you run multiple FastCGI servers on a single box. For instance, according to a tech at WestHost, 4 server instances running a large number of processes (say 15) each will frequently cause over 400MB of RAM and 1GB of swap to be used on the server, resulting in the cyclic behavior of freeing and reallocating memory. This is very resource intensive and it causes the server’s load to spike, which is problematic for any other users on the same server (in a VPS situation).

Last, but not least, configure your virtual host so that

<VirtualHost *>
    ServerName demo.mysite.com
    ServerAlias www.demo.mysite.com
    DocumentRoot /var/www/demo/
</VirtualHost>

becomes

<VirtualHost *>
    ServerName demo.mysite.com
    ServerAlias www.demo.mysite.com
    DocumentRoot /var/www/demo/public/
    ErrorLog /var/www/demo/log/server.log
    <Directory /var/www/demo/public/>
      Options ExecCGI FollowSymLinks
      AllowOverride all
      Allow from all
      Order allow,deny
    </Directory>
</VirtualHost>

Save the file as you exit and then test it to make sure you didn’t screw anything up before restarting Apache:

[mod_fastcgi-2.4.2]$ apachectl configtest
Syntax OK
[mod_fastcgi-2.4.2]$ apachectl restart

Hang in there, we’re almost done. To set up Rails to use FastCGI, we need to edit the .htaccess file in your public folder:

[mod_fastcgi-2.4.2]$ pico /var/www/demo/public/.htaccess

In that file, change

RewriteRule ^(.*)$ dispatch.cgi [QSA,L]

to read

RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]

Then save when you exit.

Finally, we need to set up the Ruby-FastCGI Gem

[mod_fastcgi-2.4.2]$ gem install fcgi -- --with-fcgi-dir=/usr/local/fcgi

Once that’s done, edit the dispatch.fcgi file in your public directory

[mod_fastcgi-2.4.2]$ pico /var/www/demo/public/dispatch.fcgi

to use the Gem by changing

require File.dirname(__FILE__) + "/../config/environment"
require 'fcgi_handler'

to

require 'rubygems'
require_gem 'fcgi'
require File.dirname(__FILE__) + "/../config/environment"
require 'fcgi_handler'

Step 6: Let’s get rolling

Finally we are in a position to test our install. To do so, we’ll add a simple controller to our demo Rails install. We start by moving into the demo folder

[mod_fastcgi-2.4.2]$ cd /var/www/demo

and then we use the Generator to make us a controller:

[demo]$ ruby script/generate controller Say

That doesn’t do a whole lot since we have no actions. Let’s define an empty one:

[demo]$ pico app/controllers/say_controller.rb

Edit the file to read

class SayController < ApplicationController
  def hello
  end
end

and save as you exit.

Now that’s all well and good, but we get an error if we try to surf to http://demo.yoursitehere.com/say/hello because there is no view associated with it. That’s easy enough to remedy, we’ll create one.

[demo]$ pico app/views/say/hello.rhtml

Type out something simple, such as

<html>
  <head>
    <title>Hello World</title>
  </head>
  <body>
    <h1>Hello from Rails!</h1>
    <p>The current time is <%= Time.now %></p>
  </body>
</html>

and then revisit http://demo.yoursitehere.com/say/hello. Now you’re rolling. Good luck and enjoy.

Addendum: What? You want MySQL?

Okay, so you want to hook up Rails to your MySQL database now. To do this, there’s a few hoops you need to jump though. First of all, you’ll need to edit your database configuration file.

[demo]$ pico config/database.yml

Fill in your database names for the development, test and production environments and the username and password for each. Then add the socket path:

development:
  adapter: mysql
  socket: /var/lib/mysql/mysql.sock
  database: your_development_db
  host: localhost
  username: root
  password: your_password

# Warning: The database defined as 'test' will be erased and
# re-generated from your development database when you run 'rake'.
# Do not set this db to the same as development or production.
test:
  adapter: mysql
  socket: /var/lib/mysql/mysql.sock
  database: your_test_db
  host: localhost
  username: root
  password: your_password

production:
  adapter: mysql
  socket: /var/lib/mysql/mysql.sock
  database: your_production_db
  host: localhost
  username: root
  password: your_password

and save as you exit. Without the socket information, Rails will never find MySQL, which sucks.

Finally, to overcome the backward-compatible password issue between Rails and MySQL, you need to install the latest MySQL Gem. Unfortunately this is easier said than done. First off, you run the install as you’d expect:

[demo]$ gem install mysql

and it spits back an error. Luckily it leaves the files where you can get to them. At present the latest version of the MySQL Gem is 2.6, so

[demo]$ cd /usr/local/ruby/lib/ruby/gems/1.8/gems/mysql-2.6

The error is because MySQL cannot be found in the regular location. We need to add a configuration parameter

[mysql-2.6]$ ruby extconf.rb --with-mysql-dir=/usr/local/mysql

and then finally

[mysql-2.6]$ make && make install

And you’re good to go.

Resources

Questions/Comments

I will be happy to take any questions or comments about this tutorial in it’s associated blog entry.