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

ServicePulse Forward Headers for Reverse Proxy Configuration

Component: ServicePulse

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

Configuration

There are two hosting options for ServiceControl, Container and Windows Service. The container is configured via environment variables, while the Windows Service is configured using command-line arguments. See the Hosting Guide for example usage of these configuration settings, along with Authentication and TLS, in a scenario-based format.

Container

Windows Service

Command-Line ArgumentDefaultDescription
--forwardedheadersenabled=trueEnable forwarded headers processing
--forwardedheaderstrustallproxies=trueTrust all proxies (auto-disabled if known proxies/networks set)
--forwardedheadersknownproxies=(none)Comma-separated IP addresses of trusted proxies
--forwardedheadersknownnetworks=(none)Comma-separated CIDR networks (e.g., 10.0.0.0/8,172.16.0.0/12)

Example:

"C:\Program Files (x86)\Particular Software\ServicePulse\ServicePulse.Host.exe" --forwardedheadersenabled=true --forwardedheaderstrustallproxies=true

What Headers Are Processed

When enabled, ServicePulse processes:

  • 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., servicepulse.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)

Interaction with the Container Built-in Reverse Proxy

ServicePulse includes a built-in YARP reverse proxy with the Container that forwards requests to ServiceControl Primary and Monitoring instances. The forwarded headers configuration does not affect this proxy.

sequenceDiagram participant Client participant Proxy as Upstream Proxy participant SP as ServicePulse participant YARP participant SC as ServiceControl Client->>Proxy: Request Note over Proxy: Sets X-Forwarded-For<br/>Sets X-Forwarded-Proto<br/>Sets X-Forwarded-Host Proxy->>SP: Request + X-Forwarded-* headers Note over SP: UseForwardedHeaders<br/>updates request context SP->>YARP: Proxied request YARP->>SC: Request to ServiceControl
  • UseForwardedHeaders processes incoming headers from an upstream proxy so ServicePulse understands the original client request (scheme, host, client IP)
  • YARP independently handles outgoing requests to ServiceControl/Monitoring backends

These operate at different points in the request flow and do not conflict.

HTTP to HTTPS Redirect

When using a reverse proxy that terminates SSL, you can configure ServicePulse to redirect HTTP requests to HTTPS. This works in combination with forwarded headers:

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

To enable HTTP to HTTPS redirect, see TLS Configuration for details on how to do this.

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 forward header configurations for different deployment scenarios.

Single reverse proxy (known IP)

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

Container:

docker run -e SERVICEPULSE_FORWARDEDHEADERS_ENABLED=true \
           -e SERVICEPULSE_FORWARDEDHEADERS_TRUSTALLPROXIES=false \
           -e SERVICEPULSE_FORWARDEDHEADERS_KNOWNPROXIES=10.0.0.5 \
           ...
           particular/servicepulse:latest

Windows Service:

ServicePulse.Host.exe --forwardedheadersenabled=true --forwardedheaderstrustallproxies=false --forwardedheadersknownproxies=10.0.0.5

Multiple reverse proxies

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

Container:

docker run -e SERVICEPULSE_FORWARDEDHEADERS_ENABLED=true \
           -e SERVICEPULSE_FORWARDEDHEADERS_TRUSTALLPROXIES=false \
           -e SERVICEPULSE_FORWARDEDHEADERS_KNOWNPROXIES=10.0.0.5,10.0.0.6 \
           ...
           particular/servicepulse:latest

Windows Service:

ServicePulse.Host.exe --forwardedheadersenabled=true --forwardedheaderstrustallproxies=false --forwardedheadersknownproxies=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:

docker run -e SERVICEPULSE_FORWARDEDHEADERS_ENABLED=true \
           -e SERVICEPULSE_FORWARDEDHEADERS_TRUSTALLPROXIES=false \
           -e SERVICEPULSE_FORWARDEDHEADERS_KNOWNNETWORKS=10.0.0.0/8 \
           ...
           particular/servicepulse:latest

Development/trusted environment

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

Container:

docker run -e SERVICEPULSE_FORWARDEDHEADERS_ENABLED=true \
           -e SERVICEPULSE_FORWARDEDHEADERS_TRUSTALLPROXIES=true \
           ...
           particular/servicepulse:latest

Windows Service:

ServicePulse.Host.exe --forwardedheadersenabled=true --forwardedheaderstrustallproxies=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