When configuring IIS (Internet Information Services) on Windows Server 2016 as a reverse proxy for Kestrel web servers, many developers encounter an issue where the X-Forwarded-Host
header isn't being forwarded to the backend servers, while other X-Forwarded-*
headers like X-Forwarded-For
and Forwarded-Proto
work correctly.
By default, IIS's Application Request Routing (ARR) module doesn't automatically forward the X-Forwarded-Host
header. This is different from other reverse proxies like Nginx or Apache, which typically forward all X-Forwarded-*
headers by default.
To fix this, you'll need to manually configure IIS to forward the X-Forwarded-Host
header. Here's how:
Method 1: Using URL Rewrite Outbound Rules
Add this rule to your web.config:
<rewrite>
<outboundRules>
<rule name="Add X-Forwarded-Host">
<match serverVariable="HTTP_X_Forwarded_Host" pattern=".*" />
<action type="Rewrite" value="{HTTP_HOST}" />
</rule>
</outboundRules>
</rewrite>
Method 2: Using Server Variables
Alternatively, you can enable the server variable:
- Open IIS Manager
- Select your server in the connections pane
- Open "Application Request Routing Cache"
- Click "Server Proxy Settings"
- Under "Allowed Server Variables", add "HTTP_X_FORWARDED_HOST"
After implementing either solution, test with a request to verify the header is being forwarded:
curl -v http://your-iis-server.com
You should now see the X-Forwarded-Host
header in your Kestrel application's request headers.
If you're using ASP.NET Core, you might want to configure the Forwarded Headers middleware:
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedHost |
ForwardedHeaders.XForwardedProto
});
Remember that proper header forwarding is crucial for applications that need to:
- Generate correct absolute URLs
- Implement proper redirects
- Maintain security headers
- Handle authentication properly
When setting up IIS as a reverse proxy for Kestrel servers, many developers notice that while X-Forwarded-For and X-Forwarded-Proto headers get forwarded automatically, X-Forwarded-Host mysteriously disappears. This isn't a configuration oversight - IIS's Application Request Routing (ARR) module handles this differently than other forwarded headers.
The X-Forwarded-Host header is crucial when your application needs to:
- Generate absolute URLs with the correct hostname
- Handle CORS policies correctly
- Maintain consistent session cookies across domains
- Implement proper redirects in multi-tenant applications
Unlike other X-Forwarded-* headers, IIS doesn't automatically forward X-Forwarded-Host. Here's how to properly configure it:
<system.webServer>
<rewrite>
<allowedServerVariables>
<add name="HTTP_X_FORWARDED_HOST" />
</allowedServerVariables>
<rules>
<rule name="ForwardedHostHeader">
<match url="(.*)" />
<serverVariables>
<set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" />
</serverVariables>
<action type="None" />
</rule>
</rules>
</rewrite>
</system.webServer>
After applying these changes, verify the headers are being forwarded correctly. In your Kestrel application, add this middleware to inspect headers:
app.Use(async (context, next) =>
{
var headers = context.Request.Headers
.Where(h => h.Key.StartsWith("X-Forwarded"))
.ToList();
// Log or debug these headers
await next.Invoke();
});
If you have multiple proxy layers, you'll need to append rather than overwrite the X-Forwarded-Host header:
<set name="HTTP_X_FORWARDED_HOST" value="{HTTP_X_FORWARDED_HOST}, {HTTP_HOST}" />
Remember to configure your Kestrel application to properly handle forwarded headers:
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.All;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
- Ensure the ARR module is installed and enabled
- Double-check server variable permissions
- Verify the rewrite module is processing the rules
- Check for conflicting rules in web.config hierarchy