How to set up HA behind a reverse proxy using IIS / ARR

I’ve just spent the best part of a day getting HomeAssistant on a Raspberry Pi to work behind an IIS ARR reverse proxy server. This involved pulling together information from a variety of posts here and elsewhere (thanks to all those who have been here before). Few people will have the same setup as me, but if you’ve got HA running on a Pi and you have a Windows server hanging around too, then you might find this step-by-step useful.

Background

I host a few public websites on a Windows 2019 IIS server, so my router forwards ports 80 and 443 to that server. But HomeAssistant is running on a separate Raspberry Pi, so I had to use a different port number to send traffic to the Pi. Having a reverse proxy on the IIS server avoids this because initially all traffic goes to IIS, and ARR then reroutes HA traffic to the Pi.

I have a domain registered (let’s call it mydomain.com) and I added subdomain ha.mydomain.com for HomeAssistant.

I have an SSL certificate for *.mydomain.com, so that already secures traffic to the IIS server. Another advantage of the reverse proxy is that once within my network, HTTPS is no longer necessary; so the final leg, from the IIS server to HA on the Raspberry Pi, can be simple HTTP, thus saving the need to configure SSL in HA.

Installation steps.

Set up a public DNS A record to point ha.mydomain.com to your router’s external IP address. ON your router, make sure all traffic on ports 80 and 443 is port forwarded to your Windows IIS server.

On the Windows server, install IIS if not already done, and also install the following IIS addons:

  • URL Rewrite
  • Application Request Routing (ARR)
  • Websocket protocol

URL Rewrite and ARR can be installed from here: Application Request Routing : The Official Microsoft IIS Site

The Websocket protocol is a Windows installation option: under Add Roles and Features, go to Server Roles, expand Web Server (IIS), then Application Development, and you’ll see it near the bottom of the list. More here: WebSocket <webSocket> | Microsoft Learn

Configuration of the IIS server

On your Windows server, open IIS, click the top-level entry for the server, and open Application Request Routing. Check Click Server Proxy Settings, and then:

  • check Enable proxy.
  • under Custom Headers, make sure X-Forwarded-For is entered under Preserve client IP …
  • uncheck Include TCP port from client IP

Apply these changes.

Now go to the Default Web Site, and add bindings for ha.mydomain.com for http (port 80) and https (port 443).

For https you will of course need an SSL certificate for *.mydomain.com. You can use a self-signed certificate if you don’t mind the browser errors, or you can buy one for about £5 a year if you shop around. Or (as in my case) your domain registrar may provide one for free, or you can use LetsEncrypt. Once you’ve got your certificate (.pfx format for IIS) install it in IIS (instructions for that are a bit beyond my scope here but are easily found elsewhere). Then make sure you select it for the https binding on your Default Web Site in IIS.

In Default Website on IIS, open URL Rewrite. On the right hand side click View Server Variables, then Add, and add this variable:

HTTP_SEC_WEBSOCKET_EXTENSIONS

Apply that change, then click Add Rules and select a blank rule. Give it a name (e.g. “HomeAssistant redirect to Raspberry Pi”), and then type any old rubbish in the Pattern field under Match URL, and more rubbish in Rewrite URL under Action. This is just to get IIS to create a web.config file if it doesn’t already exist, and to insert the necessary code framework in that file. We will then edit the file directly.

In Explorer, find web.config in your default web site folder (normally c:\inetpub\wwwroot). Open it and replace the URL Rewrite rule entry with this:

                <rule name="HomeAssistant redirect to Raspberry Pi" stopProcessing="true">
                    <match url=".*" />
                    <conditions>
                        <add input="{HTTP_HOST}" pattern="^ha\.mydomain\.com" />
                    </conditions>
                    <serverVariables>
                        <set name="HTTP_SEC_WEBSOCKET_EXTENSIONS" value="" />
                    </serverVariables>
                    <action type="Rewrite" url="http://X.X.X.X:8123/{R:0}" />
                </rule>

Obviously, substitute your domain for mydomain.com (the backslash is required because a period in a regex means “any character”); and substitute the actual local IP address of your Raspberry Pi (or whatever is running HA) for X.X.X.X. This assumes that you’re still running HA on the default 8123 port.

Note that (contrary to what is said in some posts) it is not necessary to have a separate rewrite rule to switch from https to http. The rule above will pick up all traffic to ha.mydomain.com, both http and https, and will forward it to the HA server under HTTP.

If you would like to force all external HA traffic to be under https (recommended), then you can add the following rule before the one above:

                <rule name="HTTPS Redirect" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="^OFF$" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" appendQueryString="false" />
                </rule>

It’s worth noting here the difference between action type=Rewrite and type=Redirect. The latter causes a response to go back to the user’s browser to instruct it to resubmit the request on the redirected URL (i.e. under https); whereas the former just forwards the request to the new address without telling the browser it has done it - so the browser address bar still contains the ha.mydomain.com URL, not the rewrittten one.

Configuration of the HA server

This bit is easy. Open configuration.yaml and add the following:

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - Y.Y.Y.Y
    - 127.0.0.1

where Y.Y.Y.Y is the IP address of your Windows IIS server.

Reboot the HA machine and restart IIS on the Windows machine.

And that’s it. You should now be able to go to https://ha.mydomain.com (and/or http://mydomain.com) and have HA appear.

Good luck!

1 Like

Hi Mike I’ve read your post with much interests and I want to thank you for your sharing.
I’ve a similar situation but I obtain “WebSocket connection to wss://<server.domain.com>/api/websocket failed”. Have you defined a specific rule for this?
I’m running HassWP_2021.1.1.
Thanks in advance!

Sorry Mike, resolved installing “Websocket protocol” that I thought was already installed…
Thanks…

Been fighting with this for HOURS… i was getting is error on the Token object
{ "error": "invalid_request", "error_description": "Invalid code" }
I had everything setup exactly the same as in the walk through but after I would log in i would get this in a loop
image
Finally figured it out i had to uncheck these under IIS(10) ->Server name->IIS->Application Request Routing cache->Server Proxy Settings->
image
even though it was set to “Do not cache” I hope this helps someone

Hello,
Thanks for the great post, can someone confirm if this still works, or help me out figure out why isnt this working for me?
I have setup IIS as you instructed, the only difference is that I created a site (ha) and folder ha on the “C:\inetpub\wwwroot” , and placed the “web.config” file under “C:\inetpub\wwwroot\ha”

I have HA installed in VM and the IP address of the VM is 192.168.1.40 and I can confirm I can access HA with http://192.168.1.40:8123

Address of the server that is running IIS is 192.168.1.123

Below are contents of the “web.config”:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="HTTPS Redirect" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="^OFF$" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" appendQueryString="false" />
                </rule>
                <rule name="HomeAssistant" stopProcessing="true">
                    <match url=".*" />
                    <conditions>
                        <add input="{HTTP_HOST}" pattern="^ha\.mydomain\.com" />
                    </conditions>
                    <serverVariables>
                        <set name="HTTP_SEC_WEBSOCKET_EXTENSIONS" value="" />
                    </serverVariables>
                    <action type="Rewrite" url="http://192.168.1.40:8123/{R:0}" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

what I get is:

400: Bad Request

Any idea what am I doing wrong?

Below also contents of the configuration.yaml file

Hi - sorry, it’s ages since I wrote this, and since then I’ve stopped using the IIS reverse proxy so I can’t really remember the details. But I’m a bit puzzled by your description of how you set up the folders in c:\inetpub - did you create a separate website in IIS or is this just a subfolder of the default website? Normally in IIS if you set up a new website then the folder containing the files is somewhere else (doesn’t matter where) - but having it in a subfolder of the default website seems a bit odd.

Have you tried setting it up exactly as I described, using the default website? I’d start by doing that and see if that fixes it.

Mike

Hey, so I have created a site name “ha” and also created a folder called “C:\inetpub\wwwroot\ha” and placed the web.config file inside that folder, and used the content from you on the web.config file.
I have so many reverse proxies working with this method so there must be something in the web.config file that is not correct. BTW what should be the inside:

Home Assistant URL

Also what is the method right now that you are using to access HA remotely?
I can access it by port forwarding but want to access it with https and Reverse Proxy.
Thanks.

I didn’t like the security implications having a load of port forwarding on my home router, so now I have a Wireguard VPN (via the HA plugin) and I connect remotely via the VPN. That means I only need one port open on the firewall, and that’s the one for Wireguard.

Sorry, I can’t help much further since the only notes I have about the old setup are contained in my original post! But I would certainly try setting it all up on the default website (not a subdirectory) and see if that works.

If you open the URL Rewrite rules page for your HA website in IIS, do you see the rules as per my post? if not, then it isn’t picking up that web.config and you have not set up the website correctly in IIS.

Hi, hopefully you have this working now (sorry, just saw your post). I’ve been using this IIS/ARR setup for a couple of years now (over a Hyper-V HAOS instance) and it’s still working nicely. Mine is with Win 2022, but I’d be really surprised if that makes a difference.
If yours is still not working, let me know, I’ll send what I’ve got.
P.S. My setup is VERY similar to yours - including the specific IIS web site and the https redirect.

My 2€c: I would not publish an IIS.
if you’re using Hyper-V or any other virtualization solution, I suggest to install something like skudonet/relianoid and use it to publish your services.