How to install IIS Application Request Routing in Windows Azure

A few months ago, I needed to use IIS Application Request Routing for my company’s main website, which runs in Windows Azure. We wanted to have some of the pages redirect to a different web application, but still show the  original domain name. We wanted to whitelist most of our current website, and let everything else redirect to the other site.

We could RDP into the instances of our web role and install ARR and put the configuration information for the reverse proxy into the web.config, and it worked great. The problem is whenever Microsoft installed a patch, or we published a new version, our changes would get wiped out. So I needed to figure out how to have this be installed and configured when the Azure instance starts up. I figured I could do this with a startup task in my web role, but what would I actually put in the script to do that?

I remembered something useful I saw at the MVP Summit (that wasn’t covered by NDA) – a cool website by Steve Marx (who’s on the Windows Azure team at Microsoft) showing cool things you can do in Azure, and one of them was installing ARR. He provides the basic commands needed. I’ll show you how to set up the whole process from soup to nuts.

Steve gives information both for running the web installation and for installing from an msi. I chose to use the msi, because I know I have tested that specific version, and I know the final version of my install scripts work with it. I was concerned about the links for the web installation changing or the version being updated and impacting my site, and I tend to be ultra-careful when it comes to things that could bring down my company’s website. I haven’t been called even once in the middle of the night since we moved to Azure, and I have found that I like sleeping through the night.

A prerequisite for the ARR software is the Web Farm Framework. So you need to download both of these msi’s. The only place I could find these downloads available was this blog. You’ll need the 64-bit versions, of course.

That article states that the URLRewrite module is also required, but it’s already included in Windows Azure, so you don’t have to worry about it.

So now you have your msi’s; when I downloaded them, they were called requestRouter_amd64_en-US.msi and webfarm_amd64_en-US.msi. Add the two MSI’s to your web role project. Right-click on the project and select “Add Existing Item”, and browse to them and select them. In the properties for each one, set the build action to ‘content’ and set ‘copy to output directory’ to ‘copy always’. If you don’t do this, they will not be included in your deployment, which makes it difficult for Azure to run them.

Now you need to write a startup task. I very cleverly called mine “InstallARR.cmd”. To create this, open Notepad or some plain text editor. Here is the first version of my startup task.

d /d "%~dp0"
msiexec /i webfarm_amd64_en-US.msi /qn /log C:\installWebfarmLog.txt
msiexec /i requestRouter_amd64_en-US.msi /qn /log C:\installARRLog.txt

%windir%\system32\inetsrv\appcmd.exe set config 
    -section:system.webServer/proxy /enabled:"True"  
    /commit:apphost >> C:\setProxyLog.txt

%windir%\system32\inetsrv\appcmd.exe set config 
    -section:applicationPools -applicationPoolDefaults.processModel.idleTimeout:00:00:00 
    >> C:\setAppPool.txt

exit /b 0

This didn’t work every time. The problem is that the msiexec calls run asynchronously, and they only take a couple of seconds to run. So about half the time, the second one would fail because the first one hadn’t finished yet. Since they are running as silent installs (/qn), there wasn’t much I could do about this.

I realized I need to put a pause in after each of the installs to make sure they are done before it continues. There’s no Thread.Sleep command. So the question I have to ask you here is, “Have you ever pinged one of your Azure instances?” I have, and it doesn’t respond, but it takes 3-5 seconds to tell you that. So what could I put in the script that would stop it for 3-5 seconds before actually continuing? Yes, I did. Here’s my final script, but with my service names changed to protect the innocent.

d /d "%~dp0"
msiexec /i webfarm_amd64_en-US.msi /qn /log C:\installWebfarmLog.txt
ping innocent.goldmail.com
msiexec /i requestRouter_amd64_en-US.msi /qn /log C:\installARRLog.txt
ping notprovenguilty.goldmail.com

%windir%\system32\inetsrv\appcmd.exe set config 
    -section:system.webServer/proxy /enabled:"True"  
    /commit:apphost >> C:\setProxyLog.txt

%windir%\system32\inetsrv\appcmd.exe set config 
    -section:applicationPools -applicationPoolDefaults.processModel.idleTimeout:00:00:00 
    >> C:\setAppPool.txt

exit /b 0

This worked perfectly.

Save this script as InstallARR.cmd. Add it to your project (File/AddExisting), set the build action to ‘content’ and set ‘copy to output directory’ to copy always. If you don’t do this, it won’t be included in your deployment, and Windows Azure won’t be able to run it. (Are you having a feeling of déjà vu?)

So how do you get Windows Azure to run it? You need to add it to your Service Definition file (the .csdef file in your cloud project). Just edit that file and add this right under the opening element for the <WebRole>.

<Startup>
  <Task commandLine="InstallARR.cmd" executionContext="elevated" taskType="background" />
</Startup>

Setting the executionContext to “elevated” means the task will run under the NT AUTHORITY\SYSTEM account, so you will have whatever permissions you need.

As recommended by Steve Marx, I’m running this as a background task. That way if there is a problem and it loops infinitely for some reason, I can still RDP into the machine.

I think you also need your Azure instance to be running Windows Server 2008 R2, so change the osFamily at the end of the <Service Configuration> element in the Service Configuration (cscfg) file, or add it if it’s missing.

osFamily="2" osVersion="*"

To configure the routing, add the rewrite rules to the <webserver> section of your web.config. Here’s an example. If it finds any matches in the folder or files specified in the first rule, it doesn’t redirect – it shows the page in the original website. If it doesn’t find any matches in the first rule, it checks the second rule (which in this case, handles everything not listed specifically in the first rule) and redirects to the other website.

<rewrite>
  <rules>
    <rule name="Reverse Proxy to Original Site" stopProcessing="true">
      <match url=
      "^(folder1|folder2/subfolder|awebpage.html|anasppage.aspx)(.*)" />
    </rule>
    <rule name="Reverse Proxy to Other Site" stopProcessing="true">
      <match url="(.*)" />
      <action type="Rewrite" url="http://www.otherwebsite.com/{R:1}" />
    </rule>
  </rules>
</rewrite>

Now when you publish the web application to Windows Azure, it will include the MSI’s and the startup task, run the startup task as it’s starting up the role, install and enable the IIS Application Request Routing, and use the configuration information in the web.config.

Tags:

10 Responses to “How to install IIS Application Request Routing in Windows Azure”

  1. Windows Azure and Cloud Computing Posts for 7/22/2011+ - Windows Azure Blog Says:

    [...] Shahan (@RobinDotNet) described How to install IIS Application Request Routing in Windows Azure in a 7/21/2022 post: A few months ago, I needed to use IIS Application Request Routing for my [...]

  2. Atacan Says:

    Awesome article! BTW did you try using start /wait msiexec.exe? This should AFAIK make the script blocked till the installation finishes.

  3. Publish Content to the Azure CDN with URLRewrite « Kloud Blog Says:

    [...] need to install and configure ARR and URLRewrite on a WebRole. This can be done and is detailed here so won’t be detailed [...]

  4. Richard Says:

    Very nice. I’ve got a project which uses ARR to enable sticky session load balancing on Azure: https://github.com/richorama/AzureARR
    I also re-program IIS continually to react to changes in the infrastructure.

  5. Ian Cox (@ReleaseMobiTech) Says:

    Can I suggest changing your ping code to something like
    ping 192.0.2.2 -n 1 -w 3000 1>nul ? so that you can specify how long you want it to wait

  6. Ian Cox (@ReleaseMobiTech) Says:

    Also I think d /d “%~dp0″ should be cd /d “%~dp0″

    Cheers

  7. Carl Stinson Says:

    Testing (local desktop and on Azure VM) with start /wait in batch files looks to work as required. It’s a lot cleaner than the PING wait hack too. :)

    • robindotnet Says:

      Hi Carl,
      Thank you for your feedback. In my experience, the msi packages ignore the /wait when running in a batch file, and I couldn’t ensure that the first would finish before the next tried to run, which is why I put in the ping to make it wait. I had repeated failures when trying it with /wait. Also, when you say Azure VM, is it a VM you’ve spun up yourself, or is it a cloud service? (Mine is running in a cloud service). Only other thing I can think of is they changed it in Windows Server 2012.
      Robin

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

Join 68 other followers

%d bloggers like this: