Tuesday, May 29, 2007

How to: Run Multiple Rails Apps under IIS using fast Cgi

I have found iis/aspi/fast cgi to be un-reliable, seems to crash once a week, I think it is related to a specific size of a post, But have not had the time to track it down

Update - Oct - 2007

Thanks this page seems to be quite popular

A much better/reliable solution is to use IIS with Mongrel behind it,
Check out HOW TO DEPLOY: Rails under IIS with ISAPI_Rewrite3/Mongrel

Update - Dec - 2007

I have updated this entry for rails 2.0
Check out Rails v2.0 with IIS, ISAPI_Rewrite3, Mongrel

Disclaimer

First off I dont recommend it, But if you must as dictated by an outside source here are the steps.

There are severl source's of information around but none that give and how/who with step-step details.

After accessing various sources, I finally got IIS to work "reasonably reliably", PS: Included are tips for trouble shooting permissions issues.

Background - How do you get IIS to talk to rails

When IIS sees an url like http://host/something.asp?search=abc, It looks up and sees if there is an application (dll/exe) associated with the extension .asp, if there is then it passes the request to the application associated with the extension.

So in order to run a ruby application behind iss, we need to associate a extension with "rubyw.exe" for each rails app, the extension can be anything, lets call this ".rap1" (Ruby Application 1).

Below details that steps to do this

STEP 1 - Rewrite The Url

We need to give IIS a url that looks something like http://host/something.rap1?information-for-rails-app,

But Rails generates nice looking urls, e.g. http://host/app1/controller/method, IIS allows you to re-write URL's,

So we take http://host/app1/controller/method?etc=1 and convert it to http://host/something.rap1?opnq=/controller/method?etc=1

To do this we grap "Ionic's Isapi Rewrite for IIS" (details below)

STEP 2 - Rewrite it back for Rails

But the Rails app is expecting "/controller/method?etc=1" not "opnq=/controller/method?etc=1", So you need to re-write it back in to a nice url inside rails.

To do this we patch ActionController::AbstractRequest.request_uri (see app1/lib/action_controller_request_ext.rb)

STEP 3 - app prefix the Url

Since we will be running multiple apps, we need to prefix the urls rails generates with /app1, to distinguish each application (see app1/lib/environment.rb, ActionController::AbstractRequest.relative_url_root = "/app1")

Background - Running Ruby from IIS

OK lets assume we have the url's ok, Next step is to actually run ruby (rubyw.exe) to get the app to work.

We could run rubyw directly as a cgi, but this would mean for each request, rails is started run and closed, VERY VERY Slow.

So we take "Shane Careveo's Fast CGI" dll which keeps the rails app running and simply feeds it new requests

STEP 4 - Map your extension

Using IIS Map the .rap1 extension to call the isapi_fcgi.dll. (which will call rubyw)

STEP 5 - Configure fcgi to run Ruby

Tell the isapi_fcgi.dll what ruby application to run when it gets called with a .rap1 extension, (details below)

You will also need to install ruby code, to deal with how isapi_fcgi disptaches. (see dispatch.fcgi)

STEP 6 - Permission

Fix up permissions as ruby will be run as a limited user.

Misc Notes

You can replace "opnq" in the url, with anything you like, I kept it the same as used by RORIIS, also the "something" can be any name you want, I called it fastcgi, but all we need is for IIS to look at the extension .rap1 and call isapi_fcgi.dll that in turn runs ruby!!!

Install Ruby/Rails MSSQL Software

The boring bit, This section you can skip, But was included for completeness

Install MSSQL
> dotnetfx.exe  # Install .Net Frame work 2.0 
> SQLEXPR32-SP2.EXE # MS SQl Server 2005 EXPRESS 
  # Install to "C:\Program Files\Microsoft SQL Server 2005 EXPRESS"
  # Used Named Instance "SQLEXPRESS"
  # Used mixed authentication, "sa" passsword "yourchoice"
> SQLServer2005_SSMSEE.msi # Install MS Sql Server Managment Studio
Install Ruby + Gems
> mkdir C:\ruby
> run ruby185-21.exe # Install ruby 
  # Select Install "Ruby" and "Enable RubyGems"
  # Install to "C:\ruby 
  # Check C:\ruby\bin to your everyones path !!
  
  # download rubygems, un-zip and run setup.rb
> ruby setup.rb # Install ruby gems
Install Rails
> cd C:\ruby
> gem install --include-dependencies rails # Wait may take a while !!!
> gem install --include-dependencies win32-service # pick the most recent mswin32 !!
# gem install --include-dependencies mongrel # pick the win32 pre-built
# gem install --include-dependencies mongrel_service  
Install MSSQL Drivers
# download ruby-dbi, un-zip and run setup.rb
> ruby setup.rb config --with=dbd_ado
> ruby setup.rb setup
> ruby setup.rb install
# Patch  sqlserver_adapter.rb (See Rails Ticket #7733)
> cd C:\ruby\lib\ruby\gems\1.8\gems\activerecord-1.15.3\
                  lib\active_record\connection_adapters
> edit sqlserver_adapter.rb
# Line 28x: "=~ /null/ ? nil"   ==> "=~ /null/i> ? nil"  
#    Case insensitive match on the word null
Install other gems (e.g. RMagick / Faster CSV)
# download ImageMagick and run setup.rb
> ImageMagick-6.3.0-7-Q8-windows-dll.exe 
# Tick [x] Update executable search path.

# download rmagick gem and install
> gem install rmagick --local
# Note: Documentation is in C:\ruby\lib\ruby\gems\
#    1.8\gems\rmagick-1.14.1-win32\doc\index.html

# download fastercsv gem and install
> gem install fastercsv --local
Create Rails Application and check operation
Create a basic rails app, for testing. I assume c:\rails is where your rails apps will be placed
> mkdir C:\rails
> cd rails
> rails app1 # Create rails app called app1
> ruby script/server # Run WebBrick to test 
> iexplore.exe http://localhost:3000 
  # Should get welcome page
> iexplore.exe http://localhost:3000/controller/etc
  # You should see routine error, no route found... 
  # exception from the from the rails app  
> Ctrl+break
> exit 

The Details

The original source for set-up is as follows. Thanks to all.

"Ruby On Rails For IIS Fast-CGI" (This contains all the files menthoned)

NOTE: If did not install "ROR4IISFCGI_1.0.5.exe", As the install is for a single rails application, Simply Open the file with say 7-Zip and extract. I used this file simply as the source. For each step I have detailed only the final destionation folder

The set-up process detailed below, assumes the folllowing.

  • Ruby is installed in c:\ruby
  • Your application is called "app1" and resides in c:\rails\app1, The extension nominated for is .rap1
  • Iis has C:\Inetpub as its base
  • Windows is C:\Windows

Install/Configure IaspiRewriter

The following files are installed/edited
Inetpub
Inetpub\IsapiRewrite4.dll
Inetpub\IsapiRewrite4.ini # Copied and Edited
rails
rails\app1
rails\app1\lib
rails\app1\lib\action_controller_request_ext.rb
rails\app1\config\environment.rb # Edited  
rails\app1\config\routes.rb # Edited  
Rewrite The Url
# copy/install Inetpub\IsapiRewrite4.dll, Inetpub\IsapiRewrite4.ini
> inetmgr.exe # Add url rewriter 
  # Goto:  Default Web Site -> Properties -> ASPI Filters -> Add 
    Name: IsapiRewrite4
    Exe: C:\Inetpub\IsapiRewrite4.dll  
> cd C:\Inetpub
> edit IsapiRewrite4.ini
  # Add the following rule to take urls with /app1 to call fastcgi.rap1 
  RewriteRule ^/app1(/[^.]+)$ /fastcgi.rap1?opnq=$1
  # Note: urls, with a '.' in them are not mapped. 
  # This is cool, because iis will handel serving up the the 
  # public images/css etc (see later)
> edit routes.rb  # If using Web Services. Change the .wsdl to _wsdl 
  as now cannot have a "." in a url destined for rails
  # change ':controller/service.wsdl' => ':controller/service_wsdl'

Rewrite it back for Rails
# copy/install rails\app1\lib\action_controller_request_ext.rb
> cd C:\rails\app1\config
> edit environment.rb
  # Add the following line to the section titled 
  # "Include your application configuration below"
  require 'action_controller_request_ext.rb'
app1 prefix the Url
> cd C:\rails\app1\config
> edit environment.rb
  # Add the following line to the section titled 
  # "Include your application configuration below"
  ActionController::AbstractRequest.relative_url_root = "/app1" 
      if ENV['RAILS_ENV'] == 'production'

Install/Configure FastCGI

The following files are installed/edited
Inetpub
Inetpub\isapi_fcgi.dll
Inetpub\wwwroot
Inetpub\wwwroot\fastcgi.rap1 # Created manually
rails
rails\app1
rails\app1\FastCGI.reg # Created manually 
rails\app1\public
rails\app1\public\dispatch.fcgi
ruby
ruby\lib
ruby\lib\ruby
ruby\lib\ruby\site_ruby
ruby\lib\ruby\site_ruby\1.8
ruby\lib\ruby\site_ruby\1.8\fcgi.rb
ruby\lib\ruby\site_ruby\1.8\i386-msvcrt
ruby\lib\ruby\site_ruby\1.8\i386-msvcrt\fcgi.so
Windows
Windows\System32
Windows\System32\libfcgi.dll
Windows\System32\msvcp71.dll # if not already present
Windows\System32\msvcr71.dll # if not already present
Configure fastcgi to run Ruby

Place settings in the register to tell isapi_fcgi which ruby app to run based on the file extension it is called as

> copy files as indicated above ...
> echo "# fastcgi" > C:\Inetpub\wwwroot\fastcgi.rap1 # Simply a dummy file
> edit/create C:\rails\app1\FastCGI.reg
# Place the following in the file. 

# These registry settings tell isapi_fcgi.dll what rails 
# app to run based on what file extension it is called with

[HKEY_LOCAL_MACHINE\SOFTWARE\FastCGI]
[HKEY_LOCAL_MACHINE\SOFTWARE\FastCGI\.rap1]
@=""
"BindPath"="Rails-FCGI-app1"
"AppPath"="C:\\ruby\\bin\\rubyw.exe"
"Args"="C:\\rails\\app1\\public\\dispatch.fcgi"
"Environment"=hex:52,41,49,4c,53,5f,45,4e,56,3d,70,72,6f,64,75,63,74,69,6f,6e,0d,0a,00
"StartServers"=dword:00000003
"IncrementServers"=dword:00000001
"MaxServers"=dword:00000006
"MaxProcMem"=dword:00000064
"Timeout"=dword:00000258

# The key "Environment" contains "RAILS_ENV=production\r\n\0" 

> cd C:\rails\app1\
> FastGGI.reg # Load details into the widows registry
Configure/Map your extension IIS

We will Map a Virtual directory to our application, Map the extension .rap 1 to our application

> inetmgr.exe # Add in your application to Virtual dir 
  # Goto:  Default Web Site -> New Virtual Directory -> 
    Name -> app1
    Path -> C:\rails\app1\public
    Permissions -> Read
>  netmgr.exe # Add in your application extension .rap1
  # Goto:  Default Web Site -> Properties -> Home Directory 
         -> Configration -> Mapping -> Add
    Executable -> C:\Inetpub\isapi_fcgi.dll
    Extension -> ".rap1"  # with the "."
    Script Engine -> Ticked
    Check the File Exists -> Ticked
  # If the OK button is gray, (bug in IIS 5.1)
      click on the Executable File Name a 2nd time 
  # Ensure Cache ISAP Extensions is Ticked 
Configure Permissions (the messy bit)

Your app wont run yet, as rubyw will be running as a restricted user. Perform the following steps. We will set-up a group called "Rails" and assign the IIS process user "IWAM_computername" to this group.

> compmgmt.msc
  # Goto: Local Users and Groups -> New Group -> Rails
  # Add new Rails group (with no members)   
> compmgmt.msc
  # Goto: Local Users and Groups -> IWAM_computername -> 
  #       Properties -> Member Of -> Add -> Rails

Configure iis to run application's as the local user "IWAM_computername". This makes managing permissions simpler.

> inetmgr.exe 
  # Under Server 2003+ 
    # Goto:  Application Pools -> 
       DefaultAppPool -> Properties -> Identiry 
    # Change to "IWAM_computername" 
  # Under XP 
    # Goto:  Default Web Site  ->  Properties ->
         Home Directory -> Identiry 
    # Application protection to "Medium (Pooled)"" 

Server 2003+ only, Configure IIS to accept the dll's and rubyw.exe application

# Under Server 2003+ (Only)
> inetmgr.exe  # Set permissions on applications
  # Goto:  Web Server Extension -> Add Web Server Extension 
    Name: Rails
    Files: Inetpub\IsapiRewrite4.dll, 
           Inetpub\isapi_fcgi.dll, 
           Windows\System32\libfcgi.dll, 
           C:\ruby\bin\rubyw.exe
    Status: Allowed
Set premissions on the required files/dirs for the "Rails" group

Dont forget this step otherwise your application will not run !!!

  • Give FULL permission for C:\rails\app1\temp and C:\rails\app1\log
  • Give FULL permission to TEMP (C:\WINDOWS\TEMP)
  • Give FULL permission to any other folders your rails app1 writes to (e.g C:\rails\app1\public\attachments )
  • Check Read/Execute permissions for all the .dll's menthoned above and rubyw.exe
  • Check Read permission Under HKEY_CLASSES_ROOT\ADODB.Connection for both the ADODB.Connection and ADODB.Connection.X.X entries # mssql only
  • Check Read permission Under HKEY_LOCAL_MACHINE\SOFTWARE\FastCGI # this should be ok

Test It

Perform the following steps to test it works.

Ist check your app still works with WebBrick (see above Installing Ruby etc)

> iisreset.exe # Re-start iis
> iexplore.exe http://localhost/app1/controller/etc
# You should see routine error, no route found... 
# If so you have an exception Message from the Rails app, cool !!! 
# If you get fast cgi error or page not found, 
#        check out trouble shooting. 

Configure Your Second Application

Simply repeat the steps above (that relate to a specific application) for your application. Assgning your own name and extension.

Simply change "app1" to your application name and".rap1" to your nominated extension

I would not recommend using .asp/.aspx extension, quite yet, mind you with ruby/rails going so well, it wont be long before the .aspx extension will become un-used. :-)

NOTE: Do make sure you change the "BindPath"="Rails-FCGI-app1" in the registry for fast CGI for each application, otherwise you may end up with one app's url going to another.

Trouble shooting

Some trouble shooting tips.

First off, Does rubyw start within iis.
  • Grab "Process explorer" from sysinternals
  • run "procexp.exe"
  • Right click headings and choose select columns, Add "User Name"
  • Reset iis. (iisreset.exe)
  • navigate to http://localhost/app1/controller/etc
  • watch the dllhost.exe within svchost.exe,
    • does rubyw.exe appear then disappear, If so possibly a permissions thing, does the rubyw.exe user, have permissions to all the files.
    • It does not appeara Check the fcgi set-up.
Try running your app as a restricted user.

Try the following to run your app as a restricted user. It might highlight some things

  • Create a user called IWAM_TEST (give it a password)
  • Remove IWAM_TEST from the Users group
  • Add IWAM_TEST to the Rails group
  • Now Run your app as IWAM_TEST using WebBrick
  • > runas /user:IWAM_TEST cmd 
    # You should get another cmd window as this user, 
    > env 
    # Look at the env, look ok. 
    > cd \rails\app1
    > ruby script/server
    # Look at the output, Does it say "unable to access log file" 
    # If so fix permissions
    
    Navigate to http://localhost:3000/controller/etc
    
    # Any more messages
    > Ctrl+break # break out of WebBrick
    > exit  
    
    

Conclusion

I hope this write up helps some. It helped me.

I know there is not much documentation on multiple apps and IIS.

I have done it, but think IIS -> Apache -> Mongrel would be a better choice.

All comments welcome

An Update

There is one small change you need to make to cgi.rb to make fastcgi more reliable. Check out Running Rails Apps More Reliability under IIS

8 comments:

Murray Speight said...

An update by the author, there is one small change you need to make to cgi.rb to make fastcgi more reliable.
Check out Running Rails Apps More Reliability under IIS

Anonymous said...

Hi, rioutyrr [url=http://icyfchapman.org]generic lorazepam[/url] cheap ativan Play Casino Game [url=http://dbsearchexpert.com]Casino Game Download[/url] http://dbsearchexpert.com - Play Casino Games http://thefoundationhouse.org - Celebrex Online [url=http://thefoundationhouse.org]Celebrex Online Pharmacy[/url] Cheap Celebrex http://billselleck.net - celexa drug [url=http://billselleck.net]celexa pills[/url] celexa without prescription cialis sale [url=http://nascarforums.org]cialis 20mg[/url] http://soccervid.info - cialis cost http://bloopddl.com - cheap cipro [url=http://poweryourpocket.com]ciprofloxacin online[/url] cheap cipro buy clomiphene [url=http://grandavenuemcalester.org]clomid fertility drug[/url] http://azglea.org - clomiphene citrate http://southernutahbaseballacademy.com cymbalta - cymbalta drug [url=http://southernutahbaseballacademy.com cymbalta]generic cymbalta[/url] duloxetine generic doxycycline chlamydia [url=http://cultureloungeonline.com]doxycycline without prescription[/url] http://ifso2008.org - doxycycline price http://black-harvest.com - cialis online [url=http://black-harvest.com]cheap cialis[/url] cheap levitra order cheap effexor [url=http://blackchambers-online.com]effexor on line[/url] http://blackchambers-online.com - order venlafaxine http://calzadocomplot.com - buy klonopin online [url=http://calzadocomplot.com]klonopin pill[/url] klonopin mg vardenafil 20mg [url=http://mainstreetcapital.org]levitra price[/url] http://jo3design.com - order levitra http://llfancentral.com - generic lexapro [url=http://llfancentral.com]lexapro sale[/url] lexapro sale Buy Lipitor Online [url=http://boulderwinefest.com]Buy Cheap Lipitor Online[/url] http://boulderwinefest.com - Lipitor Online Pharmacy http://thebestcheesecake.com - buy meridia online [url=http://hotbikequincy.com]meridia cost[/url] reductil online cheap nolvadex [url=http://pie-place.com]tamoxifen citrate[/url] http://pie-place.com - cheap tamoxifen http://houseofeclectic-chic.com - buy cheap phentermine [url=http://bronchitismiraclecure.com]phentermine no prescription[/url]

Dean said...

greetings to all.
I would first like to thank the writers of this blog by sharing information, a few years ago I read a book called guanacaste costa rica in this book deal with questions like this one.

tusa said...

Fantastic task ! Your site has presented me the majority of the know-how I required .
mesquite locksmiths
Opa locka FL Locksmith
Locksmith Fremont CA
San Jose locksmith
Palo Alto locksmith
Milpitas locksmith
Locksmith Mesquite tx
pembroke pines fl locksmith
plano locksmith
aventura locksmith
hialeah locksmith
locksmith aventura
miami beach fl locksmith
locksmith pembroke pines
locksmith fort worth
Hialeah FL Locksmith
fort worth locksmiths
pembroke pines locksmith
locksmith plano tx
locksmith hialeah
locksmith fort worth tx
hialeah locksmiths
miami beach locksmiths
locksmith fort worth fl
locksmith fort worth

nikeairmaxshoe said...

Be fast to browse the newest styles and lots of affordable outfits and Nike oxygen Max and women's merchandise is not an daily affair, for that reason that in the stress of modern day time girls ordinarily do not possess a complete great offer time and vitality to go buying by means of countless many style malls, and look at special fees will make you exhausted, so which you can acquire a satisfactory goods, call up for to devote lots of time, the show up of on collection buying significantly minimizing the inconvenience of this, now you not just can every one of the sudden go to to lots of goods Nike Air Max Shoes .

sping.chen said...

Ah good exciting content! Will always come to our attention. To bring you good news-works perfect! Nike Football Cleats best shoes 2011!! And Nike Mercurial Vapor Superfly.Nike soccer cleats with New nike soccer shoes or Nike mercurial soccer cleats .

somnus11258 said...

Such a nice post, We loved it a great deal!I am a china tour lover,You can learn more: China vacation packages | China city tours | China Travel Agency

Learn Chinese language on hanbridgemandarin said...

Hanbridge is the best place of Mandarin learning in Shenzhen. The quality of our staff, our unique teaching methodology and our custom-designed courseware make our school more effective than our competitors.



More Chinese learning tags : Chinese Online Learning | Chinese Online Courses | study mandarin online

Google