IIS as reverse proxy with SSL offloading

Windows_logo_-_2012I recently set up a microsoft IIS 7.5 as reverse proxy. The setup is straight forward, but there can be an issue if you want to send all the traffic from the reverseproxy encrypted via SSL to the actual webserver. Especially with self signed certificates on your backend servers it becomes a bit of a hassle. This will be a problem if you use SSL offloading which means that ISS is terminating SSL client request and forwards the HTTP request in a new SSL session protected by the destination servers self signed SSL certificate.

Everything you have to know is that the self signed SSL certificate has to be imported to your computer certificate store (not the user store!). Plus the certificate has to be valid: make sure it is not expired. And last but not least: the server has to be resolved with the certificates subject name – it will not work if you enter the IP-Adress of your HTTPs server or your server is called server1.local and your certificate says server1!

If that information already solved your problem you do not have to read further, everyone else gets a bit more of a detailed explanation:

 

Set up IIS as a reverse proxy

All you have to do is install the Application Request Routing module to your IIS. The ARR module has to be downloaded from microsoft.com and can not be added as a role service for IIS.

 

Configure IIS as a reverse proxy

Bind SSL to your IIS website

First your IIS website has to be bound on port 443 HTTPs. You can use a self signed certificate or buy one from a well known certificate authority. If you use a self signed, please make sure your certificate subject matches with your website URL. This link may be helpful: How to create self signed certificates with alternate host name.

To edit the sites binding open IIS manager and click with your right mouse button on the website and go to edit bindings. Then you have to select an IP-Adress and a certificate which your proxy will present when a client requests HTTPs.

Your site binding should look like the configuration on the picture:

SSL_binding_iis

Configure the rewrite rule

To configure the rewrite rule to achive the functionality of a reverse proxy, go to your website in the IIS management tool. Then click on the “URL Rewrite” module as shown on the next picture. (on the right side you can see the Browse Website – make sure it is bound to 443)

iis_setup

 

 

Choose “reverse Proxy” rule:

reverse_proxy_config1

Now the actual configuration starts. Enter your server name and the port where SSL is bound to. In my case it is 443. Please do not get confused by the SSL offloading explaination. HTTP requests are not necessarily transported over plain HTTP, if you specify the port an SSL tunnel will be established to transport your HTTP pakets encrypted. If you untick SSL offloading the ARR module just forwards your packets to the backend server – then the SSL certificate of your backend server will be presented to client!

reverse_proxy_config2

When you edit the rule later in expert view it should look like on this picture:

reverse_proxy_config3

Import certificates:

Unless you have public signed certificates or you already trusted your private certificate authority you have to import the SSL certificates of your backend servers to the local computer store. If you run a lot of backend HTTPs servers I suggest to create a private CA. If you run 2-3 servers you can easily do it manually or in case you set it up for testing purposes, a self signed certificate is perfectly fine.

  1. Run certmgr.msc
  2. add Snap-in certificates
  3. select computer account
  4. import the self signed certificate into “trusted root store”

Possible error:

If the IIS is not able to verify the certificate of the backend HTTPs server it will deliver an error message to the requesting client. The error message contains “HTTP Error 502.3 – Bad Gateway, A security error occurred, Error Code 0x80072f8f”. Remember: The server name you send the request to has to be the same as the subject name of your self signed SSL certificate and the certificate has to be valid – it must not be expired!

error_502_badgateway_certificate_chain

  • Son Le

    How does this work with a wildcard cert? I am getting the 502.3 bad gateway error with the 80072f8f while trying to pass clients onto a nginx web server with the same SSL certificate already in place.

  • lhomas

    so it is a certificate signed by a trusted certificate authority?
    is DNS set up properly?
    reverseproxy.tld.com (public ip address) –> nginx.tld.com (what ip are you using there?)

    • S.L

      Hello,
      Background:
      -COMODO issued Wildcard Cert through namecheap.

      -Certificate was imported into ARR node, including supplied chain from namecheap.
      -8 other nodes are IIS that have the same cert & chain applied, connects to the ARR and works fine.
      -1 node (this current one i’m having issue with) worked fine up until 9 days ago. Runs nginx 1.6.2 and hosts owncloud 8.2.2. I exported the PFX from the ARR/IIS server with private key, imported it to the NGINX server. Used the openssl commands to extract the public cert/CA-chain/private key, combined the cert+chain and configured nginx/owncloud to use that cert-chain and key.

      DNS:
      -DNS is hosted on windows server and for our tld. com forward lookup zone, I have nginx.tld. com pointed to an internal address of (10.x.x.x).
      -ARR node has it’s 80/443 ports forwarded to our firewall, which then the firewall does Nat-ing/public IP interfacing.
      -Externally Namecheap has our nginx.tld. com pointed to our public IP that is set on our firewall’s public interface. The firewall should then forward requests directly to the ARR node for processing.

      —Results
      -Owncloud works internally via https as the nginx.tld. com is pointed internally.
      -Externally when trying to get to nginx.tld. com, it redirects to https and gives me the 502.3 0x80072f8f – a security error occurred.

      I’ve noticed that internally, when looking at the certificate, the connection is encrypted using: ECDHE:RSA:AES128:GCM:SHA256; while, externally: ECDHE:RSA:AES256:CBC:SHA256. Not sure if this makes a difference.