Howto: Set up an SSL Offload / Termination Proxy with IIS 7

An SSL termination proxy is a service that sits in front of your web server and converts HTTPS requests to plain HTTP, by offloading the SSL decryption to a separate machine or process. They are commonly used for internet-facing websites, but usually with separate servers. Here’s a quick guide how you can set up your own local SSL termination proxy using IIS to simulate — for development purposes — a production webserver environment.


Pre-requisites: Install Rewrite + ARR IIS Features

First, we need to install and enable a couple of IIS features that will make this all work:

  1. Download and install the URL Rewrite and Application Request Routing (ARR) IIS 7 features.
  2. Open the IIS Management Console (inetmgr) > expand your machine > Application Request Routing Cache > right click, Server Proxy Settings… > check Enable Proxy.

Part One: Reverse Proxy Incoming HTTP Requests

Assume we have the following two IIS websites set up:

  1. The real site, containing your app or content, bound on HTTP port :80
  2. The SSL termination proxy, simply a website pointing to an empty directory, bound on HTTPS port :443

First we need to ensure requests arriving at the HTTPS:443 site are proxied through to the HTTP:80 site. We can do this by creating a web.config in the root of the HTTPS:443 IIS site with a single rewrite rule that catches all requests and rewrites them to the HTTP:80 URL:

<configuration>  <system.webServer>    <rewrite>      <rules>        <rule name="Reverse Proxy" patternSyntax="ECMAScript" stopProcessing="true">          <match url="(.*)" />          <!-- Redirect all requests to non-HTTPS site. -->          <action type="Rewrite" url="http://localhost:80/{R:1}" logRewrittenUrl="true" />        </rule>      </rules>    </rewrite>    <handlers>      <clear />      <!-- No other handlers required. Must clear them otherwise ASP.NET might try to intercept *.svc paths etc. -->      <add name="Rewrite" path="*" verb="*" modules="RewriteModule" resourceType="Unspecified" />    </handlers>  </system.webServer></configuration>

Part Two: Block non-HTTP Connections to Deal Service

On the real production hardware, only HTTPS connections will be allowed. We can simulate this on our local IIS by setting up a rewrite rule that will block any request that does not have the X-ARR-SSL HTTP header which indicates it has been routed through ARR.

This rewrite rule should be added to the HTTP:80 site’s web.config:

<system.webServer>  <rewrite>    <rules>      <rule name="Block Non-SSL Requests" patternSyntax="Wildcard" stopProcessing="true">        <match url="*" />        <conditions>          <add input="{HTTP_X_ARR_SSL}" pattern="*|*" negate="true" />        </conditions>        <action type="CustomResponse"                statusCode="403"                statusReason="Forbidden: This site requires SSL."                statusDescription="This site is currently configured to only accept connections                                   through a local SSL termination proxy (IIS Application Request                                   Routing + Rewrite modules). Any HTTP requests that do not                                   include a valid X-ARR-SSL header are blocked." />      </rule>    </rules>  </rewrite></system.webServer>

The rewrite rule also contains a nice descriptive error message to explain what’s going on if you start getting random 403 errors.

(Note that, as you’ve probably already figured out, anyone can fool this blocking rule by simply populating the X-ARR-SSL header themselves. This is an insecure blocking method that should never be used on production hardware!)

Part Three (Optional): WCF Configuration

If you’re exposing WCF services through the SSL termination proxy, you may need to add the following attribute to your operation contracts:

[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]public class MyService : IMyService{    ...}

Without this attribute WCF will refuse to process requests with a different original URL than what it expects from the binding configuration.

Acknowledgements: This guide was originally based on Ruslan Yakushev’s guide to Reverse Proxy with URL Rewrite v2 and Application Request Routing.