IIS7.x, Server Farms and Ruby

(Caution: Ruby application names are as prolific, esoteric and funny as Microsoft code names)

The previous post (broadly) demonstrated how to use a combination of URL Rewrite and FastCGI to put a Ruby on Rails application on IIS7.5.

As Rails, Merb (which I am reliably informed is what all the cool kids use today) and Sinatra

Another more common method of deploying Rails applications is behind a small web server such mongrel, thin or whilst development ruby’s inbuilt WEBrick. These servers are attached to one instance of the ruby application with a front-end web server acting as the reverse proxy server. This server forwards requests from the outside world to one of the instances of your ruby application; and ‘proxies’ the response back to the browser on the client.

Using an reverse proxy server architecture provides various goodness: easy instance creation, simple scaling and relatively easy deployment. If you get the configuration right.

To deploy a reverse proxy server with IIS previously required third party ISAPI such as ISAPIRewrite.

As complex deployments are becoming more common, Microsoft has released the Microsoft Application Request Routing Version 1 for IIS 7 (get it here). Note that the server also requires URL Rewrite.

The following is my simple setup.

How to Setup

As I have mongrel installed on my development machine, and am experimenting with sinatra: mongrel is chosen as the default server.

With a simple batch script, I launch the instances of my simple application. The ruby application is hi.rb. In this instance, ruby.exe is in my PATH. The '-p 4567' tells Sinatra and Mongrel to use port 4567 as the listening port. There are mechanisms to make these services. This machine is development only, so I’ll leave that alone

 @ECHO OFF
ruby.exe hi.rb -p 4567

Install Microsoft Application Request Routing Version 1 for IIS 7. Note that the server also requires URL Rewrite.

Launch the Internet Information Services (IIS) Manager

Create a Server Farm. A farm is a collection of servers (IIS7 and others) the server is going to farm the incoming requests to

ServerFarm-1

Provide a name for your farm

ServerFarm-2

On my test server, I wish to use multiple ports on the same server. That is, more than one application instance bound to separate ports.

Type the address (without the port) of an application instance. After clicking “Add”, click on the entry in the server address, and click on the “Advanced settings… ”. Sinatra’s default port for an instance is :4567. As extra instances are added; add them to the farm with the appropriate port.

NOTE 1: The UI when adding a httpPort for each address is a little weird. What I found working is to type the Server address:, expand ‘applicationRequestRoutin’, enter the port (if not the default port 80), click add. Then re-click on the entry in the list, and re-enter the httpPort (as it seems to revert back to :80)

NOTE 2: Each server address must be unique in the Server farm. Therefore, if you have multiple instances of the same application, although on separate ports, on the same server: you will need to do some work on the DNS or hosts file. On my test machine, I have created aliases in my machine’s hosts file to the same server (run Notepad.exe as administrator!):

 %windir%\System32\drivers\etc\hosts
127.0.0.1    localhost localhost-1 localhost-2

Server farms can also exist across physical IP addresses: this may be different IIS instances, different virtual machines or different physical machines.

ServerFarm-3

To match the incoming requests with a particular farm, a URL Rewrite Rule is automatically created.

ServerFarm-4

 

 

 

The below rule will matching any incoming request (which you may wish to tweak) to the server farm. Note the Action properties: pointing to a particular farm, passing on the {R:0}, or the pattern matched in the Match URL:

ServerFarm-5

The .config file

The configuration (on my machine) looks something like:

 %windir%\System32\inetsrv\config\applicationHost.config

<webfarms> 

    <webfarm enabled="true" name="localhost"> 
        <server enabled="true" address="localhost-1">

            <applicationrequestrouting httpport="4567" />

        </server>

        <server enabled="true" address="localhost-2">

            <applicationrequestrouting httpport="4568" />

        </server>

        <applicationrequestrouting>

            <loadbalancing algorithm="WeightedRoundRobin" />

            <protocol httpversion="Http10" />

        </applicationrequestrouting>

    </webfarm>

    <applicationrequestrouting>

        <hostaffinityproviderlist>

            <add name="Microsoft.Web.Arr.HostNameRoundRobin" />

            <add name="Microsoft.Web.Arr.HostNameMemory" />

        </hostaffinityproviderlist>

    </applicationrequestrouting>

</webfarms>

For Further Research

  • The Server Farms have extra features for checking the health of instances. Wiring these into mongrel would be cool.
  • Load Balancing mechanisms: wiring these for deeper integration
  • IronRuby. Now that would be cool.