skip to Main Content

I’m having some trouble to set up a Blazor server app to receive the real IP Address in a docker compose configuration with nginx in a reverse proxy configuration. The blazor app is running in an specific ipam network configuration. The Blazor app seems to be receiving nginx private IP Address inside the docker configuration, instead of the external client IP Address.

I have tried nearly everything I found in Google:

  1. added the options.ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor; flags and app.UseForwardedHeaders(); in the Blazor Program.cs file
  2. Added the previous ipam ip addresses to Blazor’s KnownProxies and `KnownNetworks
  3. Added the real_ip_header and set_real_ip_from in the nginx.config as suggested by many answers I found on Google
  4. Added proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; to the nginx.config file to forward the Client IP Address

But the Blazor server, which is listening in port 5077 always retrieves the proxy address, 127.28.1.1 which corresponds with the Docker ipam network, instead of the Client Ip Address, which in my case should be 127.0.0.1 as I’m running docker in my local machine.

enter image description here

I will attach the configuration I have as well as a .zip with all the reprocucible project in case:

Program.cs:

using Microsoft.AspNetCore.HttpOverrides;
using NginxBlazorTest.Data;
using System.Net;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();


builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    //options.ForwardedHeaders = ForwardedHeaders.All;

    options.ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor;
    //options.ForwardLimit = null;
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();

    options.KnownProxies.Add(IPAddress.Parse("::ffff:172.28.1.0"));
    options.KnownProxies.Add(IPAddress.Parse("::ffff:172.28.1.1"));
    options.KnownProxies.Add(IPAddress.Parse("::ffff:172.28.1.2"));
    options.KnownProxies.Add(IPAddress.Parse("::ffff:172.28.1.3"));
    options.KnownProxies.Add(IPAddress.Parse("172.28.1.0"));
    options.KnownProxies.Add(IPAddress.Parse("172.28.1.1"));
    options.KnownProxies.Add(IPAddress.Parse("172.28.1.2"));
    options.KnownProxies.Add(IPAddress.Parse("172.28.1.3"));
    

    options.KnownNetworks.Add(new Microsoft.AspNetCore.HttpOverrides.IPNetwork(IPAddress.Parse("::ffff:172.28.0.0"), 8));
    options.KnownNetworks.Add(new Microsoft.AspNetCore.HttpOverrides.IPNetwork(IPAddress.Parse("::ffff:172.28.0.1"), 8));
    options.KnownNetworks.Add(new Microsoft.AspNetCore.HttpOverrides.IPNetwork(IPAddress.Parse("::ffff:172.28.0.2"), 8));
    options.KnownNetworks.Add(new Microsoft.AspNetCore.HttpOverrides.IPNetwork(IPAddress.Parse("::ffff:172.28.0.3"), 8));
    options.KnownNetworks.Add(new Microsoft.AspNetCore.HttpOverrides.IPNetwork(IPAddress.Parse("172.28.0.0"), 8));
    options.KnownNetworks.Add(new Microsoft.AspNetCore.HttpOverrides.IPNetwork(IPAddress.Parse("172.28.0.1"), 8));
    options.KnownNetworks.Add(new Microsoft.AspNetCore.HttpOverrides.IPNetwork(IPAddress.Parse("172.28.0.2"), 8));
    options.KnownNetworks.Add(new Microsoft.AspNetCore.HttpOverrides.IPNetwork(IPAddress.Parse("172.28.0.3"), 8));    
});

var app = builder.Build();
app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseStaticFiles();
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();

DockerFile:

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 5077

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Debug
WORKDIR /src
COPY ["NginxBlazorTest/NginxBlazorTest.csproj", "NginxBlazorTest/"]
RUN dotnet restore "./NginxBlazorTest/./NginxBlazorTest.csproj"
COPY . .
WORKDIR "/src/NginxBlazorTest"
RUN dotnet build "./NginxBlazorTest.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Debug
RUN dotnet publish "./NginxBlazorTest.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "NginxBlazorTest.dll"]

docker-compose.yml:

version: '3.4'

services:
  nginxblazortest:
    container_name: nginxblazortest
    image: ${DOCKER_REGISTRY-}nginxblazortest
    build:
      context: .
      dockerfile: NginxBlazorTest/Dockerfile
    networks:
      - frontend_network 
    environment:
      - ASPNETCORE_ENVIRONMENT=Development      
      - URLS=http://+:5077;   
      - HTTP_PORT:5077;
 
  nginx:
      container_name: nginx
      image: nginx:alpine     
      networks:
      - frontend_network 
      ports:
      - 80:80
      - 8080:8080
      - 443:443
      volumes:
      - ./Nginx/nginx.conf:/etc/nginx/nginx.conf:ro  
      - ./Nginx/proxy_params:/etc/nginx/proxy_params:ro  
      depends_on:
      - nginxblazortest      
networks:
  frontend_network: 
     ipam:
      driver: host
      config:
        - subnet: 172.28.1.0/16
          ip_range: 172.28.1.0/24   

volumes:
  conf:
    driver: local      
  vhost:
    driver: local      
  certs:
    driver: local
  html:
    driver: local

nginx.conf:

user nginx;

events 
{
    worker_connections 4096;
}

http 
{ 
    proxy_set_header Host $host;
    proxy_pass_request_headers on;

    upstream nginxblazortest 
    {
        server nginxblazortest:5077;        
    }

    server {
        listen 80;
        listen [::]:80;

        server_name localhost 127.0.0.1;

        set_real_ip_from  172.28.1.0;
        set_real_ip_from  172.28.1.1;
        set_real_ip_from  172.28.1.2;
        set_real_ip_from  172.28.1.3;
        set_real_ip_from  172.28.1.0/16;
        set_real_ip_from  172.28.1.0/24;
        set_real_ip_from  127.0.0.1;
        set_real_ip_from  ::1;    
        set_real_ip_from  ::ffff:172.28.1.0;
        set_real_ip_from  ::ffff:172.28.1.1;
        set_real_ip_from  ::ffff:172.28.1.2;
        set_real_ip_from  ::ffff:172.28.1.3;
        set_real_ip_from  ::ffff:172.28.1.0/16;
        set_real_ip_from  ::ffff:172.28.1.0/24;
        set_real_ip_from  ::ffff:127.0.0.1;
        real_ip_header    X-Forwarded-For;
        real_ip_recursive on;

        location / {      
            include proxy_params;
            proxy_pass http://nginxblazortest/;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

Any help would be greatly appreciated, thanks in advance!

2

Answers


  1. In your docker-compose.yml, you’ve used ipam with a custom subnet and IP range.If you don’t have a specific need for this, consider removing the custom IPAM configuration and let Docker handle the networking. only add the IP of your NGINX container to the KnownProxies. In the nginx.conf, you have multiple redundant lines like proxy_set_header X-Real-IP $remote_addr;.

    http {
           ...
           upstream nginxblazortest {
               server nginxblazortest:5077;        
           }
    
           server {
               ...
               set_real_ip_from  172.28.1.0/24;
               real_ip_header    X-Forwarded-For;
               real_ip_recursive on;
    
               location / {      
                   include proxy_params;
                   proxy_pass http://nginxblazortest/;
                   proxy_set_header X-Real-IP $remote_addr;
                   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
               }
           }
       }
    

    Remove all known proxies and networks except the Docker subnet.

    builder.Services.Configure<ForwardedHeadersOptions>(options =>
       {
           options.ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor;
           options.KnownNetworks.Clear();
           options.KnownProxies.Clear();
    
           options.KnownNetworks.Add(new Microsoft.AspNetCore.HttpOverrides.IPNetwork(IPAddress.Parse("172.28.1.0"), 24)); 
       });
    

    Make sure that no other middleware or service is adding to the X-Forwarded-For header after it gets to Blazor. try deploying the project to some different server and make a test.

    Login or Signup to reply.
  2. For debugging purpose, try and create a custom middleware in your Blazor application to log the values of the X-Real-IP and X-Forwarded-For headers. That way, you can check if these headers are reaching your Blazor application with the correct values.

    In Program.cs, after var app = builder.Build();, insert the custom middleware code:

    var app = builder.Build();
    
    // Custom middleware to log headers
    app.Use(async (context, next) =>
    {
        // Retrieve the values of the headers
        var xRealIp = context.Request.Headers["X-Real-IP"].FirstOrDefault();
        var xForwardedFor = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
    
        // Log the values of the headers
        Console.WriteLine($"X-Real-IP: {xRealIp}, X-Forwarded-For: {xForwardedFor}");
    
        // Continue processing
        await next.Invoke();
    });
    
    app.UseForwardedHeaders();
    // rest of the code
    

    Run your Blazor application and make a request to it through your Nginx reverse proxy.
    Check the console output or logs to see the values of the X-Real-IP and X-Forwarded-For headers.

    • If the middleware is logging the correct client IP address, then the headers are being forwarded correctly by Nginx, and the issue might be with how the Blazor application is processing these headers.

    • If the headers are not showing the correct IP, or are missing, then the issue might still be with the Nginx configuration, or possibly with Docker networking.

    The idea is to get a clear insight into whether the correct headers and values are reaching your Blazor application.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search