IIS is a popular web server with awesome GUI management and high performance. And sometimes we just need IIS works as a reverse proxy.

Last week, I was building Aiursoft.IO. Aiursoft.IO is a project which reverse-proxies https://probe.aiursoft.com to provide a shorter download URL. And we already have a Windows Server virtual machine and Azure App Service Plan. So we don't plan to buy an additional Linux virtual machine.

For Azure App Service based on the Windows server, the config is all shared and just runs smoothly without changing anything. So this is a great practice for us now.

Before configuring your reverse proxy, you need to install IIS first. IIS can't run as a reverse proxy without extensions. You need to install some additional packages:

In the picture, there are packages I usually install on a Windows Server. The highlighted package: RequestRouter and Rewrite are necessary. 

Those two packages can be downloaded at:

https://www.microsoft.com/en-us/download/details.aspx?id=47333

https://www.microsoft.com/en-us/download/details.aspx?id=47337

After installing it, you may see a new panel in your IIS management tools named Application Request Routing:

To enable reverse proxy, open the proxy settings:

Make sure the Enable Proxy checkbox is checked. Save the settings and reboot your IIS.

Now basic preparation is complete. To create a new reverse proxy rule, Create a new website and config the domain bindings.

In your binding settings, the domain names shall be your final front-end domain. In my example, it shall be *.aiursoft.io because I want to configure a revere proxy to proxy from https://probe.aiursoft.com/download/open/{site-name}/* to https://{site-name}.aiursoft.com/*.

After setting the domains and HTTPS cert, you can create a new file named web.config under your site root path.

First, paste the following XML to your web.config file. This content makes nothing change.

<?xml version="1.0" encoding="utf-8"?>

<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

I gonna create some new rules. First, I want to enable HTTPS access only. So I gonna redirect all HTTP traffic to HTTPS. Add the code to the <rules> tag.

        <rule name="HTTPS force" enabled="true" stopProcessing="true">
          <match url="(.*)" />
          <conditions>
            <add input="{HTTPS}" pattern="^OFF$" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
        </rule>

This matches any content without TLS encryption. And stop processing the request and redirect to the site with the same host {HTTP_HOST} and bypass the path {R:1}.

Then I gonna create the real reverse proxy logic. Add the following content to the <rules> tag.

        <rule name="Probe" stopProcessing="true">
          <match url="(.*)" />
          <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
                        <add input="{HTTP_HOST}" pattern="([_0-9a-z-]+).aiursoft.io" />
          </conditions>
          <action type="Rewrite" url="https://probe.aiursoft.com/download/open/{C:1}/{R:1}" appendQueryString="true" logRewrittenUrl="false" />
        </rule>

This stop processing requests which match the pattern: ([_0-9a-z-]+).aiursoft.io and rewrite(reverse proxy) it to real probe download address.

After writing this, the reverse proxy is working online. Aiursoft.IO is a pretty complicated example. If you want to reverse proxy Google.com, simply add:

        <rule name="Google" stopProcessing="true">
          <match url="(.*)" />
          <action type="Rewrite" url="https://www.google.com/{R:1}" appendQueryString="true" logRewrittenUrl="false" />
        </rule>

After configuring the reverse proxy, I wanna enable HSTS feature to get better security. Add the following code to your <system.webServer> tag.

Finally, your config file shall be like:

<?xml version="1.0" encoding="utf-8"?>

<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="HTTPS force" enabled="true" stopProcessing="true">
          <match url="(.*)" />
          <conditions>
            <add input="{HTTPS}" pattern="^OFF$" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
        </rule>
        <rule name="Google" stopProcessing="true">
          <match url="(.*)" />
          <action type="Rewrite" url="https://www.google.com/{R:1}" appendQueryString="true" logRewrittenUrl="false" />
        </rule>
      </rules>
    </rewrite>
    <httpProtocol>
     <customHeaders>
        <add name="strict-transport-security" value="max-age=15552001; includeSubDomains; preload" />
     </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

And just test it:

To publish your reverse proxy server to Azure App Service, simply publish the web.config file to the root folder of your app service.

To use reverse proxy in Azure app service, you need to manually enable a service called ARR. Simply open the Kudo controller, go to the folder: site.

And add a file named applicationHost.xdt with web.config. Change the content of it to:

<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <system.webServer>
    <proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="false" reverseRewriteHostInResponseHeaders="false" />
  </system.webServer>
</configuration>

Save and restart your Azure App Service. And your proxy just works.