How to Retrieve Client IP in ASP.NET Core Behind a Reverse Proxy

By FoxLearn 3/7/2025 9:27:23 AM   65
When deploying a web app with both a front-end and API back-end to Azure App Service, you may encounter an issue where the client IP address returned by your API always shows the Azure outbound IP rather than the real client IP.

This occurs when using a reverse proxy to prevent CORS issues, so your front end can call the API without exposing the actual API URL. In this article, we will discuss how to resolve this problem.

Solution

ASP.NET Core has built-in support for handling the "X-Forwarded-For" HTTP header, which is typically used by reverse proxies to forward the client's real IP address. However, when running behind Azure's reverse proxy, you need to ensure that the proxy's IP addresses are configured correctly to allow ASP.NET Core to interpret the forwarded headers properly.

1. Enable Forwarded Headers Middleware

First, configure your application to handle the forwarded headers. Add the following code in your Startup.cs or Program.cs file:

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

Next, add the middleware in the Configure method:

This ensures that the X-Forwarded-For and X-Forwarded-Proto headers are respected, but this alone isn't sufficient in the case of Azure App Service.

2. Add Azure Outbound IPs to the Configuration

Azure App Service uses multiple outbound IP addresses, so you need to configure ASP.NET Core to trust these IP addresses as known proxies.

To do this, follow these steps:

  1. Get Azure App Service Outbound IPs:

    • In the Azure portal, navigate to the "Networking" section of your App Service instance.
    • Copy the list of outbound IP addresses to your clipboard.
  2. Add Outbound IPs to appsettings.json:

Instead of hardcoding the IP addresses, you can store them in appsettings.json:

{
  "AzureKnownProxies": [
    "52.163.244.128",
    "13.75.34.175",
    "168.63.220.81",
    "207.46.136.220",
    "168.63.210.90",
    "23.101.15.21",
    "23.101.7.253",
    "207.46.136.152",
    "65.52.180.140",
    "23.101.13.231",
    "23.101.3.51"
  ]
}

3. Modify Dependency Injection Configuration:

Update your Program.cs (or Startup.cs) file to read the known proxy IPs from appsettings.json and add them to the ForwardedHeadersOptions:

var knownProxies = builder.Configuration.GetSection("AzureKnownProxies").Get<string[]>();

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
    options.ForwardLimit = null;
    options.KnownProxies.Clear();
    
    if (knownProxies != null)
    {
        foreach (var ip in knownProxies)
        {
            options.KnownProxies.Add(IPAddress.Parse(ip));
        }
    }
});

This ensures that ASP.NET Core correctly recognizes the real client IP when requests come through the Azure reverse proxy.

By following these steps, you will be able to retrieve the real client IP address in your API, even when your ASP.NET Core app is deployed behind a reverse proxy on Azure App Service. The key is configuring the ForwardedHeadersOptions to trust Azure's outbound IP addresses, allowing the app to correctly interpret the X-Forwarded-For header.