Logging the real client IP on IIS behind ARR

When IIS Application Request Routing (ARR) acts as a reverse proxy, your backend content servers log the ARR server's IP instead of your real visitors. Here's why, and how to record the true client IP in the standard IIS log using the X-Forwarded-For header.

Short answer. ARR makes a fresh request to the backend on the client's behalf, so the backend IIS server logs the ARR server's IP in c-ip. ARR forwards the visitor's address in X-Forwarded-For when the Preserve client IP proxy setting is on. Install an ISAPI filter on the backend that reads the header and writes the real address into the standard c-ip field, trusting only your ARR servers.

The problem

Application Request Routing (ARR) turns IIS into a reverse proxy / load balancer in front of one or more backend content servers. ARR receives the client request and makes a new request to the backend on the client's behalf, so the backend IIS server sees the connection coming from the ARR server. The backend's c-ip log field therefore records the ARR server's IP for every request, and geolocation, reporting and security tooling lose the real visitor.

Why it happens

The backend's network peer is the ARR server, not the client. ARR can carry the original client address to the backend in an HTTP header:

So the client IP reaches the backend in a header. But IIS doesn't read X-Forwarded-For natively. The header arrives at the content server and is ignored. That's the gap Winfrasoft X-Forwarded-For for IIS fills.

The fix: X-Forwarded-For for IIS

Install Winfrasoft X-Forwarded-For for IIS on the backend content servers (the ones doing the logging). It's an ISAPI web filter that reads the X-Forwarded-For header ARR adds and writes the real client address into the standard IIS c-ip log field, with no application changes. A Proxy Trust List of your ARR server IPs ensures only the ARR hop is trusted, so the genuine client is logged and the header can't be spoofed.

Step by step

  1. On the ARR server, confirm Preserve client IP in the following header is set to X-Forwarded-For (IIS Manager → server node → Application Request Routing Cache → Server Proxy Settings).
  2. Install X-Forwarded-For for IIS on each backend content server (IIS 10 on Windows Server 2016–2025), not on the ARR server.
  3. Add the ARR server's IP address(es) to the Proxy Trust List on the backend servers. (See the Installation & Configuration Guide for the exact trust-list format.)
  4. Run IISRESET on the backend, then browse the site and confirm the backend IIS c-ip field shows real client addresses.

Lock down the backend. So a client can't reach the content servers directly and forge an X-Forwarded-For header, restrict the backend (firewall or IIS IP restrictions) to accept traffic only from your ARR servers. Trusting only the ARR addresses is what keeps the logged client IP reliable.

Does ARR forward the original Host header too?

Client IP isn't the only thing a reverse proxy hop can obscure. If your backend application needs to know the public hostname the client actually requested (to build absolute URLs, generate correct redirects, or serve multiple external domains from one farm), that's a separate header, X-Forwarded-Host, and ARR doesn't send it by default either.

Add it the same way you'd add any other forwarded header with ARR: in URL Rewrite, open the reverse-proxy inbound rule, go to Server Variables, and add HTTP_X_FORWARDED_HOST (add HTTP_X_FORWARDED_PROTO alongside it if the backend also needs to know whether the original request was HTTPS). This is a URL Rewrite construct rather than a Server Proxy Settings checkbox, so it's easy to miss if you're expecting the same one-click toggle as Preserve client IP.

If the backend is an ASP.NET Core application, HTTP_X_FORWARDED_HOST is exactly what ForwardedHeadersOptions.ForwardedHostHeaderName reads. See the ASP.NET Core guide for the application-side configuration once ARR is sending the header.

Frequently asked questions

Does ARR forward the client IP to the backend?

Yes. ARR's server proxy settings include Preserve client IP in the following header, set to X-Forwarded-For by default. ARR adds the client's IP to that header on each forwarded request; the backend just needs to log it.

Where do I install X-Forwarded-For for IIS: on ARR or the backend?

On the backend content servers, because those are the servers whose IIS logs you want to show the real client. The ARR server only needs the "preserve client IP" header setting enabled.

What is X-ARR-LOG-ID, and does it contain the client IP?

No. X-ARR-LOG-ID is a correlation GUID that Application Request Routing attaches to each forwarded request so you can match an entry in the ARR server's log to the matching entry on the backend. The name misleads people into treating it as a logging value for the client, but it holds no address at all. The client IP travels in X-Forwarded-For. Logging both is useful: X-ARR-LOG-ID traces the request across the hop, c-ip tells you who made it.

Which addresses should I add to the Proxy Trust List?

The IP address(es) of your ARR server(s): the source the backend servers see. X-Forwarded-For for IIS then treats those as trusted and logs the first untrusted address, the real client.

Does ARR send X-Forwarded-Host by default?

No. Unlike Preserve client IP for X-Forwarded-For, there's no equivalent single setting for the Host header. Add HTTP_X_FORWARDED_HOST as a URL Rewrite server variable on the reverse-proxy inbound rule; without it, the backend only sees whatever Host header ARR forwarded, with nothing indicating the request came through a proxy at all.

Is X-Forwarded-By the same as X-Forwarded-For?

No, and they get confused. X-Forwarded-For identifies the client and the chain of proxies a request passed through. X-Forwarded-By, where anything uses it, identifies the proxy interface that handled one hop, closer to RFC 7239's by parameter on the Forwarded header. ASP.NET Core's ForwardedHeadersOptions has properties for ForwardedFor, ForwardedHost, ForwardedProto and ForwardedPrefix, but there's no built-in "ForwardedBy" equivalent, and ARR doesn't add an X-Forwarded-By header either. If you need to correlate a request across an ARR hop, X-ARR-LOG-ID is the header ARR actually provides for that.

Get X-Forwarded-For for IIS

Restore real visitor IPs in your backend IIS logs behind ARR. Available now for IIS 10 on Windows Server 2016–2025, with a free 14-day trial.

View the product   or request a download →