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.
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"">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 :
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 :
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<ConfigModel>(); 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 => { var conditions = r.GetCollection("conditions"); var condition = conditions.FirstOrDefault(c => 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
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!