Installing Phusion Passenger on CentOS 5.5

Need to run Rails apps under Apache?  Phusion’s Passenger is becoming the de-facto standard for doing so with its ease of setup, low memory footprint, and deep support.  Once you have Ruby and Rails setup on your CentOS server (see this post), you can install Passenger and integrate it with Apache.  Here’s how:

1) Install the Apache development tools
Passenger is nothing more than a dynamic shared object (DSO).  You will need the httpd-devel package to build Dynamic Shared Objects (DSOs) for Apache.  The following command will install it:

yum install httpd-devel

Depending on your server, you will notice a number of dependent packages being installed, including apr-devel, perl, and apr-util-devel.

2) Install Passenger.
Passenger is a gem, and installed in the typical fashion of any gem:

gem install passenger
Building native extensions.  This could take a while...
Building native extensions.  This could take a while...
Successfully installed fastthread-1.0.7
Successfully installed passenger-2.2.15
2 gems installed
Installing ri documentation for fastthread-1.0.7...
Installing ri documentation for passenger-2.2.15...
Installing RDoc documentation for fastthread-1.0.7...
Installing RDoc documentation for passenger-2.2.15...

3) Build Passenger for Apache
Passenger has a scripted installer. Start it with this command:

passenger-install-apache2-module

The first thing it will do is check its own dependencies. If you have everything in place, you will see this:

Follow the onscreen keyboard prompts from the script, and you will see build messages scroll quickly by as the binaries are built. If the build is successful, you will be presented with this final screen before the shell script exits:

4) Integrate Passenger with Apache
Before beginning, make a copy of your Apache httpd.conf file:

cp /etc/httpd/conf/httpd.conf httpd.conf.orig

Then edit the httpd.conf file and search for the LoadModules section. Add a directive at the end of this list to load the Passenger shared object. It should look like this:

Now scroll down to the end of the file, and add these lines to help the Passenger shared object find the ruby and gem binaries:

PassengerRoot /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.15
PassengerRuby /usr/local/bin/ruby

5) Add a symlink to your app
Change to the directory specified by the server-wide DocumentRoot directive (/var/www/html) and add a symlink to your Rails application. In this case, our Rails application lives in the /webapps/todos directory, so the symlink should link to the “public” directory of the application:

ln -s /webapps/todos/public/ todos

6) Add a virtual host directive for your Rails application
Point Apache to your Rails application:


    ServerName localhost
    DocumentRoot /var/www/html
    RailsEnv development
    
        Allow from all
        Options -MultiViews
    
     RailsBaseURI /todos

Now restart Apache with an “apachectl restart” command, and browse to your Rails app.  That’s it!

AirTran's missed technology opportunities

Let me start by saying that I love AirTran as an airline.  On a recent trip from Atlanta to New Orleans, my flight arrived early in BOTH directions.  Not an easy feat, and certainly a reason they are currently atop the annual Airline Quality Ratings published by the U.S. Department of Transportation.

Like most airlines, AirTran sends timely email notifications of special fares, and offers the ability to check-in online or at a kiosk.  When I went to check-in at a New Orleans airport kiosk, I encountered a problem that prevented me from printing my boarding pass.  After two tries, the kiosk finished by spitting out this piece of paper:

I have received a “Counter Assistance Ticket” from the kiosk.  What do you see that’s broken here?  Here’s what I see:

1)  The first sentence tells me what to do with the ticket; take it to a counter agent to help finish my check-in.  OK, I can accept that some people might need explicit instructions, so we can let this part go.

2) I take my ticket to the counter, and hand it to the customer service agent.  I proudly state that I have a “hostfail” with a reference number of NGDMJE, and hand it to her.  She takes the ticket from me, opens up a three-ring binder on her counter, and cross-references the error.

Except that didn’t happen.

She is a customer service representative, not an engineer, and has no idea what “hostfail” means.  She cannot use the ticket to help me.  Instead, she starts fresh by asking for my last name and destination.

Its clear that this error was recorded on some internal AirTran system with a reference number that could be used to directly reference (and presumably fix) it. So the ticket doesn’t help her and it doesn’t help me.  Why print it at all?  Why complicate a process and incur the expense of printing paper?  In an industry with such tight margins, I can only imagine how much money AirTran is throwing away each day with these printings.

2)  getBooking(Pricing) failed.   The security-minded part of me sees that AirTran has now revealed a method from its code, in addition to the likely hostname of the kiosk itself:  MSY-IKSKTKT04.  This is an unnecessary leakage of infrastructure information.

3)  System.OutOfMemoryException also tells me, by its syntax, that this kiosk is probably running on .NET technology. It also tells me that there is a disconnect somewhere in AirTran’s QA function which has enabled a memory leak to surface.

All this bothered me, and I decided to use Twitter to tell AirTran about it.  Many companies use Twitter for customer service functions today, and I expected nothing different.  Here’s what I saw on AirTran’s twitter page:

One tweet.  One.  From almost a full year ago.  And they have accrued 2, 612 followers during that time.  What company would not love to have almost three thousand customers waiting to interact with them?  By contrast, Delta has 744 followers, and has tweeted 58 times.

AirTran has almost four times the amount of followers that Delta has, but doesn’t use them.  Its only tweet was a version of “Hello, world” followed by a year of silence.  This is clearly a missed opportunity for AirTran to connect with its customers.

In the two touches I made to their technology stack, I saw problems AirTran could easily fix to make themselves friendlier and more useful to travelers.  Will they?

7 Steps to Rails on CentOS

Red Hat Linux (and its recompiled cousin, CentOS)  has a fantastic reputation for stability and maturity.  However, this often means that packages included with the OS are somewhat out-of-date by the time the distribution is released.  For example, the latest version of CentOS is 5.5, and the version of Ruby that ships with it is version 1.8.5, which dates back to August 2006.  Even the Ruby group recommends using nothing less than 1.8.7 for Rails development.

So how do you get the stability of Red Hat with the goodness of Ruby? Compile from source to get the latest, greatest version.  Here’s how:

1)  Install CentOS 5.5
To save yourself alot of headaches during the installation, check to see if you have the “Development Tools” group installed with this command:

# yum grouplist |grep -i Development

If you don’t have it, install the package group with this command:

#yum groupinstall "Development Tools"

Note that you may also have the older version of Ruby installed via RPM’s.  You can check to see if you have it with this command:

# rpm -qa |grep ruby

If you discover an older version, uninstall it before proceeding (rpm -e <package_name>).

2) Create a /sources directory and change to that directory.

3) Download and build Ruby.
Download the latest Ruby source code (latest version is 1.9.2-p0 as of this writing).

wget ftp://ftp.ruby-lang.org//pub/ruby/1.9/ruby-1.9.2-p0.tar.gz

Uncompress the tarball and build Ruby:

tar -zxvf ruby-1.9.2-p0.tar.gz
cd ruby-1.9.2-p0
./configure
make
make install

If you have all the proper dependencies, you should have no errors during the configure or make phases. This will install Ruby to the following directories:

/usr/local/include/ruby
/usr/local/bin/ruby
/usr/local/lib/ruby
/usr/local/share/doc/ruby/html
/usr/local/share/man1

Once the install is complete, verify the version of Ruby:

# ruby -v
ruby 1.9.2p0 (2010-08-18 revision 29036)

The Ruby source package also installs RubyGems, the Ruby package manager.  Verify the version of RubyGems:

# gem -v
1.3.7

4) Check for updated gems
Ensure you have the latest gem versions by running this command:

# gem update --system

5) Install the rake build language

# gem install rake

6) Install rails

# gem install rails

7) List the installed gems.

# gem list

That’s it! You now have a fully-installed Ruby on Rails stack.  However, Ruby also needs a back-end database and a web server for its presentation layer.   Future posts will detail how to install and integrate web server and database tiers with Rails.

SharePoint People & Groups not updating

We recently discovered a problem with user information in the “People and Groups” view of a SharePoint web application not updating. While a user’s MySite was accurately updated with a photograph, an “About me” section, and profile information, the same user in a web application People and Groups view was not updated. This updating is typically handled via the Quick Profile Synchronization timer job.

To test the problem, we tried altering a user’s photograph and “About me” text and waited an hour for the timer job to fire. Nothing changed. It appeared that the timer job did not have access to update the view, and nothing was logged to the Event or ULS logs about the problem. Here is how we fixed it:

Open Central Administration, then browse to Application Management/Content Databases and select the web application which is experiencing the problem. Ensure all of the content databases are in the “Started” state; if a database is in the “Stopped” state, the timer job will be blocked from updating the database. As you can see in the screen capture below, several of our databases were in the “Stopped” state:

The next step was to temporarily set the Quick Profile Synchronization timer job to run every 2 minutes from its default of every 59 minutes. This timer job synchronizes user information in content databases from user profile data.  Reducing this setting allowed us see that profile synchronization was working without having to wait 59 minutes for the next run.  The command to change the timing is:  stsadm -o sync -synctiming m:2

We then ran the “preparetomove” stsadm command on the database that was not being updated properly. This command temporarily stops the profile and membership synchronization service from running against the database. The syntax for this command is:

stsadm -o preparetomove -contentdb  servernameinstance:content_db_name -site http://your_site_url

After that command completes successfully, detach the database using Central Admin/Content Databases/Manage Content Database Settings. Be sure to write down the name and server location of the database.  After successfully removing the database, reattach it to the web application using the same process, but in reverse.

Once the database is attached, run the “preparetomove” command again, but with the “–undo” flag this time to undo the “preparetomove” operation:

stsadm -o preparetomove -contentdb  servernameinstance:content_db_name -undo -site http://your_site_url

After the command completes successfully, run the following stsadm command to clear all synchronization information: stsadm –o sync –deleteolddatabases 0

After that, simply wait two minutes for the timer job to fire.  Profile information should start syncing up in the People and Groups view.  Here is the view before making the change:

And here is the “after” view; note the updated photograph and “About me” entries that were successfully synchronized:

Remember to reset the Quick Profile Synchronization timer job to run at the default 59 minutes: stsadm -o sync -synctiming m:59