IIS does not set X-FORWARDED-HOST

I have an IIS server [on WinServer 2016] that acts as a reverse proxy for a few Kestrel web servers. Right now I am trying to setup IIS to forward all X-Forwarded-* headers. For X-Forwarded-For and X-Forwarded-Proto headers everything works fine but not for X-Forwarded-Host.

Here is "Allowed Server Variables" on server level:

Allowed Server Variables

Here is what I see in debugger, when HTTP request hits Kestrel webserver

HTTP headers

Unfortunately I can't create a dump from PROD servers but since a few features are not working properly, the situation should be similar to DEV environment.

After reading a few articles on how to setup IIS as a reverse proxy, I got an impression that all X-Forwarded-* headers should be added automatically. Or, is XFH an exception and I need to set it manually?

I would be really appreciated for any kind of help!


Solution 1:

This took me a while to figure out. There are some oddities with how IIS works with its Server Variables, see below:

  1. You must define the variable in the InetMgr GUI, I have found that trying to specify only using the web.config, the server will return 500 internal server errors until it's added. (You have already done this, so nothing to change here.)

  2. A value either dynamic to the request or static for every request must be assigned. This is preformed in the web.config:

Code with Markup and syntax highlighting

If you wish to copy and paste:

 <?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="ReverseProxyInboundRule1" enabled="true" stopProcessing="true">
                    <match url="(.*)" />
                    <action type="Rewrite" url="http:/example.com/{R:1}" />
                    <serverVariables>
                        <set name="ORIGINAL_HOST20" value="{HTTP_HOST}" />
                        <set name="HTTP_X_FORWARDED_PROTO" value="https" />
                        <set name="HTTP_X_FORWARDED_PORT" value="443" />
                        <set name="HTTP_X_FORWARDED_HOST" value="example.com" />
                    </serverVariables>
                </rule>
            </rules>
    </rewrite>
    <httpErrors errorMode="DetailedLocalOnly" />
    <directoryBrowse enabled="false" />
</system.webServer>

Hope this helps!

Solution 2:

I finally figured this out from a GitHub issue. I was trying to set both X-Forwarded-Host and the Host header and could get neither to work:

From https://github.com/maptiler/tileserver-gl/issues/119

A workaround for this in IIS is to force IIS to not change the Host header.

\Windows\System32\inetsrv\appcmd.exe set config -section:system.webServer/proxy -preserveHostHeader:true /commit:apphost

You can also do this from the UI:

Setting system.webServer/proxy preserveHostHeader to True

As soon as I set this and restarted the server, the variables were set correctly and the Flask app I was reverse proxying was redirecting to the correct URL (instead of localhost:8050).

Hope this helps someone. I spent countless hours just trying to get this to work.