Getting Started
Architecture
NServiceBus
Transports
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring
Modernization
Samples

ServiceControl Forward Headers for Reverse Proxy Configuration

Component: ServiceControl

When ServiceControl instances are deployed behind a reverse proxy that terminates SSL/TLS (like NGINX, Traefik, or a cloud load balancer), you need to configure forwarded headers so ServiceControl correctly understands the original client request.

Configuration

ServiceControl instances can be configured via environment variables or App.config. Each instance type uses a different prefix. See the Hosting Guide for example usage of these configuration settings in conjunction with Authentication and TLS configuration settings in a scenario based format.

What Headers are Processed

When enabled, ServiceControl instances process:

  • X-Forwarded-For - Original client IP address
  • X-Forwarded-Proto - Original protocol (http/https)
  • X-Forwarded-Host - Original host header

When the proxy is trusted:

  • Request.Scheme will be set from X-Forwarded-Proto (e.g. https)
  • Request.Host will be set from X-Forwarded-Host (e.g. servicecontrol.example.com)
  • Client IP will be available from X-Forwarded-For

When the proxy is not trusted (incorrect KnownProxies):

  • X-Forwarded-* headers are ignored (not applied to the request)
  • Request.Scheme remains http
  • Request.Host remains the internal hostname
  • The request is still processed (not blocked)

HTTP to HTTPS Redirect

When using a reverse proxy that terminates SSL, ServiceControl instances can be configured to redirect HTTP requests to HTTPS. This works in combination with forwarded headers:

  1. The reverse proxy forwards both HTTP and HTTPS requests to ServiceControl
  2. The proxy sets X-Forwarded-Proto to indicate the original protocol
  3. ServiceControl reads this header (via forwarded headers processing)
  4. If the original request was HTTP and redirect is enabled, ServiceControl returns a redirect to HTTPS
sequenceDiagram participant Client participant Proxy as Reverse Proxy participant SC as ServiceControl Client->>Proxy: HTTP Request Note over Proxy: Terminates request<br/>Sets X-Forwarded-Proto: http Proxy->>SC: Request + X-Forwarded-Proto: http Note over SC: Reads X-Forwarded-Proto<br/>Detects original was HTTP SC-->>Proxy: 301 Redirect to HTTPS Proxy-->>Client: 301 Redirect to HTTPS Client->>Proxy: HTTPS Request Note over Proxy: Terminates SSL<br/>Sets X-Forwarded-Proto: https Proxy->>SC: Request + X-Forwarded-Proto: https SC->>Client: Response (via Proxy)

To enable HTTP to HTTPS redirect, see TLS Configuration.

Proxy Chain Behavior (ForwardLimit)

When processing X-Forwarded-For headers with multiple IPs (proxy chains), the behavior depends on trust configuration:

ConfigurationForwardLimitBehavior
TrustAllProxies = truenull (no limit)Processes all IPs, returns original client IP
TrustAllProxies = false1 (default)Processes only the last proxy IP

For example, with X-Forwarded-For: 203.0.113.50, 10.0.0.1, 192.168.1.1:

  • TrustAllProxies = true: Returns 203.0.113.50 (original client)
  • TrustAllProxies = false: Returns 192.168.1.1 (last proxy)

Configuration examples

The following examples show common forwarded headers configurations for different deployment scenarios using the primary ServiceControl instance.

Single reverse proxy (known IP)

When running behind a single reverse proxy with a known IP address:

<add key="ServiceControl/ForwardedHeaders.Enabled" value="true" />
<add key="ServiceControl/ForwardedHeaders.TrustAllProxies" value="false" />
<add key="ServiceControl/ForwardedHeaders.KnownProxies" value="10.0.0.5" />

Multiple reverse proxies

When running behind multiple proxies (e.g. load balancer and application gateway):

<add key="ServiceControl/ForwardedHeaders.Enabled" value="true" />
<add key="ServiceControl/ForwardedHeaders.TrustAllProxies" value="false" />
<add key="ServiceControl/ForwardedHeaders.KnownProxies" value="10.0.0.5,10.0.0.6" />

Container/Kubernetes environment

When running in a container environment where proxy IPs are dynamic, trust a network range:

<add key="ServiceControl/ForwardedHeaders.Enabled" value="true" />
<add key="ServiceControl/ForwardedHeaders.TrustAllProxies" value="false" />
<add key="ServiceControl/ForwardedHeaders.KnownNetworks" value="10.0.0.0/8" />

Development/trusted environment

For development or fully trusted environments (not recommended for production):

<add key="ServiceControl/ForwardedHeaders.Enabled" value="true" />
<add key="ServiceControl/ForwardedHeaders.TrustAllProxies" value="true" />

Troubleshooting

HTTPS redirect loops

Symptom: Browser shows "too many redirects" or redirect loop errors when accessing the application through a reverse proxy with SSL termination.

Cause: The X-Forwarded-Proto header is not being processed, so the application thinks the request is HTTP and keeps redirecting to HTTPS.

Solutions:

  • Verify forwarded headers are enabled
  • Check that the proxy IP is in KnownProxies or KnownNetworks, or enable TrustAllProxies
  • Confirm the reverse proxy is sending the X-Forwarded-Proto header

Wrong host in generated URLs

Symptom: Links or redirects use the internal hostname (e.g. localhost or container name) instead of the public hostname.

Cause: The X-Forwarded-Host header is not being trusted or processed.

Solutions:

  • Verify the proxy IP is trusted (check KnownProxies/KnownNetworks configuration)
  • Confirm the reverse proxy is sending the X-Forwarded-Host header
  • In Kubernetes, ensure the correct pod/node network is in KnownNetworks

Client IP shows proxy IP instead of real client

Symptom: Logs or audit trails show the proxy's IP address instead of the actual client IP.

Cause: The X-Forwarded-For header is not being processed, or the wrong IP is being extracted from a proxy chain.

Solutions:

  • Verify forwarded headers are enabled and the proxy is trusted
  • For proxy chains, check the ForwardLimit behavior — with TrustAllProxies=false, only the last proxy IP is used
  • If using multiple proxies, ensure all proxy IPs are listed in KnownProxies

Headers not processed in Kubernetes

Symptom: Forward headers work locally but not in Kubernetes, even with headers enabled.

Cause: In Kubernetes, the ingress controller or load balancer IP may differ from what's configured in KnownProxies.

Solutions:

  • Use KnownNetworks with the pod/service CIDR range instead of specific IPs (e.g. 10.0.0.0/8)
  • Check what IP the request is actually coming from (ingress controller pod IP, node IP, or load balancer IP)
  • For development/testing, temporarily enable TrustAllProxies=true to confirm headers are the issue

Verifying header processing

To confirm whether forwarded headers are being processed correctly:

  1. Enable verbose logging to see incoming request details
  2. Check that Request.Scheme shows https (not http) when accessing via HTTPS-terminating proxy
  3. Verify the Host header in logs matches the expected public hostname
  4. Compare client IP in logs against the expected client IP

Related Articles