Azure Site Extensions : Application Request Routing

 

Do you know that Application Request Routing is available on Azure WebApp?

Last year, I needed something to create a simple DNS Gateway. I decided to looked at the Azure WebApp. My first choice was to create some custom API that will act as a proxy, but the performance was bad. Then I’ve seen that ARR was available on Web App and so I’ve just to configure my Web.config correctly to route request.

The aims was to realize the same thing that this old project that I currently use in production : https://sg.codeplex.com/ but host all in the Azure Web Site.

 

image

All the bits are available on GitHub :

https://github.com/jdevillard/AzureProxyAdminConsole

Activate Proxy functionnality

In azure Web Site, Rewrite Rule and ARR are enabled but you need to activate the proxy  functionality. To do this, you need to use the Azure Site Extensions Transform File.

You need to create a applicationHost.config file in your site folder with the following content :

<?xml version="1.0"?>
<configuration xmlns:xdt="<a href="http://schemas.microsoft.com/XML-Document-Transform&quot;">http://schemas.microsoft.com/XML-Document-Transform"</a>>
<system.webServer>
<proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="false"
reverseRewriteHostInResponseHeaders="false" />
<rewrite>
<allowedServerVariables>
<add name="HTTP_X_ORIGINAL_HOST" xdt:Transform="Insert" />
<add name="HTTP_X_UNPROXIED_URL" xdt:Transform="Insert" />
<add name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" xdt:Transform="Insert" />
<add name="HTTP_ACCEPT_ENCODING" xdt:Transform="Insert" />
<add name="HTTP_REFERER" xdt:Transform="Insert" />
</allowedServerVariables>
</rewrite>
</system.webServer>
</configuration>

Then you can create your rewrite rule.

for my test I’ve configured a custom DNS pointing to my azure web app and I’ve set routing based on my sub dns

Rewrite Rule

a rewrite rule example could be :

<rule name="internal" patternSyntax="ECMAScript" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="test1.mycustomdns.net" />
</conditions>
<serverVariables>
<set name="HTTP_X_UNPROXIED_URL" value=<a href="https://myproxywebsite.azurewebsites.net/{R:1}">https://myproxywebsite.azurewebsites.net/{R:1}</a> />
<set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
<set name="HTTP_X_ORIGINAL_HOST" value="{HTTP_HOST}" />
<set name="HTTP_ACCEPT_ENCODING" value="" />
<set name="HTTP_REFERER" value=<a href="https://myotherwebsite.azurewebsites.net/{R:1}">https://myotherwebsite.azurewebsites.net/{R:1}</a> />
</serverVariables>
<action type="Rewrite" url=<a href="https://myotherwebsite.azurewebsites.net/{R:1}">https://myotherwebsite.azurewebsites.net/{R:1}</a> />
</rule>

The different property are :

<add input=”{HTTP_HOST}” pattern=”test1.mycustomdns.net” /> to configure the pattern of the Request
<set name=”HTTP_X_UNPROXIED_URL” value=https://myproxywebsite.azurewebsites.net/{R:1} /> to create custom header that allow destination site to know the unproxied_url
<set name=”HTTP_REFERER” value=https://myotherwebsite.azurewebsites.net/{R:1} /> HTTP referer allow us to force the header value to avoid problem with api call
   <action type=”Rewrite” url=https://myotherwebsite.azurewebsites.net/{R:1} /> specify the destination site. The {R1} parameter is here to copy the url (after the host)

Azure Web App Extension

To avoid configuring the Web.config file, I’ve created an Azure Web Site Extensions with a minimal form to configure the Proxy.

The first thing is to create an Azure Web Site Extensions, for this I use the well documented wiki of the kudu Team :

https://github.com/projectkudu/kudu/wiki/Azure-Site-Extensions

Then you have to deploy the extensions on the WebSite, because It’s not on the gallery, you need to copy the all the bits on your FTP.

After that, the extension will be available on you kudu site :

image

 

when you start the Admin Console, you will be redirect to the yousite-scm.azurewebsites.net/ProxyAdminConsole

This sub site is just an MVC application that provide a list of the redirection and a form to create new redirection  :

image

 

This will use the Microsoft.Web.Administration library to edit & configure the web.config of the site.

For example, here is how I get the different rewrite rule to provide a list of configured rules:

private static string webSiteName = Environment.ExpandEnvironmentVariables("%APPSETTING_WEBSITE_SITE_NAME%");

// GET: Configure
public ActionResult Index()
{
var list = new List&lt;ConfigModel&gt;();

using (var serverManager = new ServerManager(Environment.ExpandEnvironmentVariables(@"%APP_POOL_CONFIG%")))
{
var path = @"Web.config";

var sites = serverManager.Sites;
var webConfig = serverManager.GetWebConfiguration(webSiteName);
string rulesSection = "rules";
var inboundRulesCollection =
webConfig.GetSection("system.webServer/rewrite/" + rulesSection).GetCollection();
var outboundRulesSection = webConfig.GetSection("system.webServer/rewrite/outboundRules");
var outboundRulesCollection = outboundRulesSection.GetCollection();
var preConditionsCollection = outboundRulesSection.GetCollection("preConditions");

inboundRulesCollection.ForEach(
r =&gt;
{
var conditions = r.GetCollection("conditions");
var condition = conditions.FirstOrDefault(c =&gt; c.GetAttribute("input").Value.ToString() == "{HTTP_HOST}");
list.Add(new ConfigModel()
{
RuleName = r.GetAttribute("name").Value.ToString(),
Pattern = condition != null ? condition.GetAttribute("pattern").Value.ToString() : string.Empty,

});
})
;

}
return View(list);
}

 

With this library, you can add/remove other rules, and because the web.config is modified, the Azure WebApp is automatically restart to take care of the new configuration.

All the project is available on the github repo : https://github.com/jdevillard/AzureProxyAdminConsole

This entry was posted in ASP.NEt, Azure, English and tagged , , . Bookmark the permalink.

1 Response to Azure Site Extensions : Application Request Routing

  1. davidebbo says:

    In the allowedServerVariables, please change “Insert” to “InsertIfMissing”. We’ve seen cases where sites break after using this because another xdt (e.g. from ApplicationInsights) also adds those, and they end up duplicated. InsertIfMissing takes care of it. Would be great if you could update your post to reflect that. Thanks!

Leave a comment