| Home | Free Articles for Your Site | Submit an Article | Advertise | Link to Us | Search | Contact Us |
This site is an archive of old articles

    SEARCH ARTICLES
    Custom Search


vertical line

Article Surfing Archive



Deploying Ruby on Rails Applications to Microsoft IIS and Windows Server - Articles Surfing


The process I've followed here has worked on IIS on Windows 2000 Server, Windows XP and now Windows Server 2003. I don't know which versions of IIS were involved but the same basic process has been used across all three. I've not quite managed to get web services working over IIS but I reckon I'm not far away - so follow the instructions below and I'll update you when we get there.

So where do we begin? First of all, collect all your bits and bobs together. In particular you will need

* the Ruby Installer http://rubyforge.org/frs/download.php/4174/ruby182-15.exe
* the Rails Framework http://rubyforge.org/frs/download.php/7655/rails-1.0.0.zip
* the Ruby DBI-ADO Interface http://ruby-dbi.rubyforge.org/ (if you are using SQL Server)
* Ruby for IIS http://rubyforiis.sosukodo.org/
* FastCGI for IIS http://www.caraveo.com/fastcgi/
* and the Ionic Rewriter http://cheeso.members.winisp.net/dl/IonicIsapiRewriter.zip

Ruby is for obvious reasons.

Rails is useful as I found that 2003 is so locked down that gem did not have access to download the framework from rubyforge.

The DBI-ADO interface is needed for a single file, ADO.rb, that allows the SQL Server adapter to connect to MS-SQL.

Ruby for IIS does some patching to Rails and Ruby to allow IIS to route its requests to FastCGI and eventually to Rails. In the interests of full disclosure I should say that I have not looked at the source of this and so do not know exactly how it works. I will get round to it, promise.

FastCGI keeps a number of Ruby/Rails processes running within IIS. This means that when a request comes in from a client you do not need to start a new Ruby process (and hence incur the not insignificant cost of loading all the libraries) every time. Instead FastCGI starts N processes and if all are busy will start more, upto a maximum of M processes and routes requests to whichever process is free.

The Ionic Rewriter takes a Rails-friendly url (controller/action/id) and rewrites it into a form that IIS understands. IIS then dispatches this new URL to FastCGI which in turn passes it to Ruby.

So, you've installed Rails (into C:\Ruby) and copied your application files over (into D:\MyApp). You've added the Rails framework into your application's vendor folder (D:\MyApp\vendor) - this is because we will be altering some of the framework files so we want to keep our changes (in D:\MyApp\vendor) separate from the main Rails installation (in C:\ruby\lib\ruby\gems\1.8\gems). You then need to extract ADO.rb from the DBI file and place it in C:\ruby\lib\ruby\site_ruby\1.8\DBD - you will need to create an ADO folder and place the file into there.

Next up, edit your application's configuration file (either one of the environment specific ones, or your general one - you decide) and add the line:

ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:tmpdir] = 'D:\\Temp\\'

You will need to create a Temp folder on D: or your application will silently fail to work. The point of this is to force Ruby to place its session files into a known folder - if you read back through this blog you will find that at one point I was having strange behaviour with sessions. It turns out that as you run under different configurations (CGI, FastCGI and WEBrick) Ruby sometimes places its files in different locations and you get unpredictable behaviour. Plus it also helps when you need to clean up your sessions (which you will need to do later).

Now run your application under WEBrick. This is vital. If it doesn't work here it definitely won't work under IIS. Don't say I didn't warn you. What? It didn't work under WEBrick. I bet you forgot to edit your database.yml file. Go and do it now and test it again. Still doesn't work? Seems to fail silently with no entries in your log file. I told you - create a D:\Temp folder and you should be OK.

Copy your ISAPI files to a safe place - I tend to put them in C:\InetPub - they are associated with IIS but not available to the public. This means copying your FastCGI.DLL and IsapiRewrite4.DLL and IsapiRewrite4.INI files to wherever. Watch out, the Ionic Rewriter DLL and INI file must live in the same folder.

Fire up the trusty pain-in-the-arse Internet Information Services configuration manager. The instructions here are for setting up one site on the "Default Web Site" - I don't think it will be too hard to set up multiple Rails sites on one IIS site and even easier to set up multiple IIS sites, each containing a single Rails site. But I've not done it so I won't go on about it here.

Right-click on your "Default Web Site" and select "Properties". Select ISAPI Filters. Click Add and enter a filter name of "Rewriter" and select the IsapiRewrite4 DLL.

Next, switch to the "Home Directory" tab. Make sure "a directory stored on this computer" is selected and set D:\MyApp\Public as the local path. Put your application name into "Application Name" (if this is greyed out then click "Create" to set up the site as an application) and make sure "Scripts and Executables" is selected for "execute permissions". Next up, click "Configuration". Under "Mappings" click "Add" and select FastCGI.DLL as the executable, .fcgi as the extension (if you are going to have multiple Rails applications on a single server you need to vary this extension on a Rails-application-specific basis - for example .myapp1, .myapp2 etc), with "All Verbs", "Script Engine" and "Check that file exists" all selected.

If you're on Server 2003 there is an extra step. You have to allow IIS access to the executables you are going to be using. Create a new Web Server Extension in the IIS Configuration Manager, calling it "MyApp". Add FastCGI.DLL, IsapiRewriter4.DLL and RubyW.exe to this extension and make sure that it is enabled.

Phew - what have we done so far?

* We've installed Rails and our application and made sure it works OK under WEBrick
* We've told IIS that the default web site for this server is our application's public folder
* We've told IIS that any request to the default web site should be fed through the Ionic Rewriter
* We've told IIS that any request for a .fcgi file should be fed through FastCGI

What we've not done is tell Ionic or FastCGI how to behave.

Ionic first. Edit IsapiRewrite4.INI - get rid of the contents of the file and replace it with

# Ruby on Rails
IterationLimit 0
RewriteRule ^(/[^.]+)$ /dispatch.fcgi?$1

This takes the URL that IIS recieves and matches it against the given regular expression. I'm no grexpert but I'm reliably informed that it matches any string starting with a '/' that does not contain '.'s. If you are setting up a web-service then this has an implication - by default Rails makes the WSDL available via a URL ending in service.wsdl. You will need to edit D:\MyApp\config\routes.rb to change this to something like service_wsdl - otherwise the URL rewriter will spot the '.' and will not feed the request to Rails at all. (Of course, I haven't got web services working with these instructions yet). Anyway, so it matches any URL starting with a '/' and not containing a '.' - and rewrites it to /dispatch.fcgi?$1. So /controller/action/id will be matched to /dispatch.fcgi?/controller/action/id.

Hang on - our URL is being rewritten with a .fcgi in it - ring any bells? That's right, next up we configure FastCGI. Open RegEdit and open the Local Machine/Software key. Create a key (folder) called "FastCGI". Under here create another key (folder) called ".fcgi" - when FastCGI is invoked with a file extension of .fcgi it will use the settings in this key. This is why, when we have multiple applications on a single server, we need to vary the file extensions (.myapp1, .myapp2 as detailed above - likewise we need to rename dispatch.fcgi to dispatch.myapp1/dispatch.myapp2 for each respective application). The basic FastCGI setttings we need (we'll add some more later) are:

* AppPath - set this to C:\ruby\bin\rubyw.exe
* Args - set this to D:\MyApp\public\dispatch.fcgi
* BindPath - set this to MyAppRailsCGI

AppPath tells FastCGI that we want Ruby (the "windows" version that does not produce a command line output) to execute our scripts, passing it the Args (our dispatch.fcgi script) as the entry point to the application, using the Named Pipe "MyAppRailsCGI" to communicate.

Now, use the IIS Configuration thingy to restart IIS - right-click on the Server, select All Tasks and restart. This seems to take forever on Server 2003. Now open your favourite browser and point it at your application (http://myserver/controller/action/id or whatever). Now I'm betting that you get a "recognition failed for dispatch.fcgi".

Let's take a walk on the dark side. I'm not 100% sure what is going on here. It involves regular expressions and environment variables that I can't access in debug mode and it all seems to happen before Rails' logging is invoked. So this is guesswork that seems to be effective. Go to D:\MyApp\vendor\actionpack-version\lib\action_controller\request.rb - this is the Ruby file that ActionPack uses to route URL requests. Under Apache and WEBrick, it returns the REQUEST_URI environment variable, and if it can't get at it, it manipulates PATH_INFO and SCRIPT_NAME to get the same result. Under IIS it doesn't work - what the method is expecting is a "SCRIPT_NAME" of "/dispatch.fcgi" (which is what we have) but a "PATH_INFO" of "/dispatch.fcgi/controller/action". In other words, instead of extracting the original URL and making it into a query string, it expects the original URL to be tacked onto the end of the dispatcher script. The problem with this is that if the URL looks l!
ike that, then the URL no longer ends with .fcgi so IIS does not know to ask FastCGI to process the request. Our PATH_INFO looks more like "/dispatch.fcgi?/controller/action" - note the all important question mark in the URL. However, if we modify the request_uri method in request.rb to look like:

# Returns the request URI correctly, taking into account the idiosyncracies
# of the various servers.

def request_uri
if uri = env['REQUEST_URI']
(%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri # Remove domain, which webrick puts into the request_uri.
else
# REQUEST_URI is blank under IIS - get this from PATH_INFO and SCRIPT_NAME
script_filename = env['SCRIPT_NAME'].to_s#.match(%r{[^/]+$})
uri = env['PATH_INFO']
uri = uri.sub("#{script_filename}", "") unless script_filename.nil?
uri
end
end

I'm 99% sure that this edit is what is making the web-services fall over. However, it does mean that traditional sites (that don't use query strings) are routed correctly.

Restart IIS (again .. yawn) and try connecting once more. After a long pause (as FastCGI invokes Ruby for the first time) you should see your application. Congratulations. Have a cup of tea.

Now to reconfigure FastCGI again ... reopen RegEdit and move to your .fcgi key. Add entries for StartServers (DWORD), IncrementServers (DWORD) and MaxServers (DWORD). This tells FastCGI how many copies of Ruby to start initially (I tend to use 5), how many to start at times of high load (I tend to use 3) and the maximum number of Ruby processes to have running at one time (15 if your server can handle it). I also tend to set the Timeout (DWORD) to 600 - if FastCGI needs to start extra Ruby processes it will keep them alive for ten minutes before shutting them down again. And your last one - add a BINARY key called Environment - and type in RAILS_ENV=PRODUCTION for the value. In Regedit you can directly enter the value for binaries by typing in the right hand side of the edit box - you don't need to convert each character into Hex, like I did the first time I was confronted with this editor!

And there you have it. Your Rails application (sans web-services) should be up and running on your IIS server. It should have 5 concurrent Ruby processes dealing with incoming requests, increasing to 15 processes under load.

Hope that helps ... enjoy.

Oops - almost forgot. Create a batch file (D:\MyApp\Scripts\cleanup.cmd) that contains the line del D:\Temp\Ruby_Sess*.*. Then add a scheduled task to run that batch file every night at some god-forsaken hour. This cleans up Ruby's session files and prevents too many from being created. Of course, ideally, you would examine the last-changed-time and only delete those that hadn't been touched in twenty minutes, or whatever, but, for my application at least, getting rid of all of yesterday's sessions is good enough. Your mileage may vary.

Rahoul Baruah, Ruby on Rails Development at http://www.3hv.co.uk/


Submitted by:

Rahoul Baruah

Rahoul Baruah has been using Ruby on Rails commercially since 2005 and is available for hire (either as a developer or to troubleshoot your Rails project) at http://www.3hv.co.uk/



        RELATED SITES






https://articlesurfing.org/computers_and_internet/deploying_ruby_on_rails_applications_to_microsoft_iis_and_windows_server.html

Copyright © 1995 - Photius Coutsoukis (All Rights Reserved).










ARTICLE CATEGORIES

Aging
Arts and Crafts
Auto and Trucks
Automotive
Business
Business and Finance
Cancer Survival
Career
Classifieds
Computers and Internet
Computers and Technology
Cooking
Culture
Education
Education #2
Entertainment
Etiquette
Family
Finances
Food and Drink
Food and Drink B
Gadgets and Gizmos
Gardening
Health
Hobbies
Home Improvement
Home Management
Humor
Internet
Jobs
Kids and Teens
Learning Languages
Leadership
Legal
Legal B
Marketing
Marketing B
Medical Business
Medicines and Remedies
Music and Movies
Online Business
Opinions
Parenting
Parenting B
Pets
Pets and Animals
Poetry
Politics
Politics and Government
Real Estate
Recreation
Recreation and Sports
Science
Self Help
Self Improvement
Short Stories
Site Promotion
Society
Sports
Travel and Leisure
Travel Part B
Web Development
Wellness, Fitness and Diet
World Affairs
Writing
Writing B