Custom Domain Names and Reverse Proxies for Azure Functions

05/11/2016

In this post I will demonstrate how to assign a custom domain name for your dynamic Azure function with an ARM template. I will also show a neat trick on how using a reverse proxy you can get your Azure Functions to look like they are part of an existing Azure Web App.

Reverse proxies comes in many flavors, most well-known are probably nginx, but that is a unix product and doesn’t really fit the functions ecosystem (although you could host it an a docker container somewhere, alternatively there are also SaaS solutions cloud be used for the purpose, e.g. cloudflare).

But Internet Information Services(IIS) can also act as a reverse proxy, by using the URL Rewrite extension. This extension is available on all azure web apps, so any Azure Web site can in fact be used as a reverse proxy, also for other purposes than the one demonstrated here. All we have to do is assign our custom domain to an Azure web app and enable the URL rewrite extension and setup the rewrite rules in the web.config.

Enough background let’s get going. We are going to create are the following:

I have created a github repository with the ARM template containing the Azure Web App and a Dynamic Function App and the very tiny web project that is to be deployed to the azure web app to configure the web.config for url rewrite. I will not post the template in its entirety here, just highlight a few important things.

Before you deploy the ARM template, you need to setup a CNAME for the domains you want to use that points to .azurewebsites.net and your-function-app.azurewebsites.net, otherwise the ARM template won’t be able to automatically setup the domain names. When using the ARM template you can provide the domain name you want to use for the reverse proxy web site, in the webAppName parameter, I used sjkpfunwithfunctions and for the functionApp in the functionAppName parameter I used sjkptestfunction.

I would like my web to be available at http://functions.sjkp.dk so I have the following setup with my DNS provider
dns-configuration
You need to make a similar setup for the function app if you are going to assign it a custom domain name too.

In my ARM template I add the following the web app resource, to get ARM to configure the domain name for the web app
[js]
{
"apiVersion": "2015-08-01",
"type": "hostNameBindings",
"name": "[parameters(‘webAppDomainName’)]",
"dependsOn": [
"[concat(‘Microsoft.Web/sites/’, parameters(‘webAppName’))]"
],
"tags": {
"displayName": "hostNameBinding"
},
"properties": {
"domainId": null,
"hostNameType": "Verified",
"siteName": "variables(‘webAppName’)"
}
}
[/js]

You need to change the webAppDomainName parameter of the template to whatever domain name you decide on, I used functions.sjkp.dk, and if you want your functionApp to also have a custom domain name assigned you need to provide its name in the functionAppDomainName parameter. In reality, you probably don’t need to assign a custom domain name if you are going to hide it behind the reverse proxy, but I wanted to include it in this blog post, to show that it is indeed possible.

Then you are ready to deploy the ARM template (just make sure the DNS changes have propagated before you do).

Setting up the Reverse Proxy

I haven’t found a way to fully automate the configuration of the reverse proxy. I use the site extension reverseproxy to enable the URL rewrite extension on the web app.
[js]
{
"apiVersion": "2015-08-01",
"name": "reverseproxy",
"type": "siteextensions",
"dependsOn": [
"[resourceId(‘Microsoft.Web/Sites’, parameters(‘webAppName’))]"
]
},
[/js]

But that alone is not enough, we need to make some modifications to the web.config of the site. This is the part that I haven’t been able to automate because the web.config needs to know the full url of the function app, and I haven’t found a way to parameterize it.

[xml]
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect" enabled="true" stopProcessing="true">
<match url="^api/?(.*)" />
<action type="Rewrite" url="https://[YOUR-FUNCTION-APP-URL].azurewebsites.net/api/{R:1}" />
<serverVariables>
<set name="HTTP_ACCEPT_ENCODING" value="" />
</serverVariables>
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
[/xml]

So be sure to replace the url in the web.config before you publish the web app project to the Azure web app.

Once the web project has been published you can browse the test function at http://yourdomain/api/TestFunction?name=Hello but also on http://yourcustomfunctiondomain/api/TestFunction?name=Hello sweet isn’t it. Of course you can setup SSL as well e.g. by using my site extension that leverages free Lets Encrypt certificates.