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:
- added the
options.ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor;
flags andapp.UseForwardedHeaders();
in the BlazorProgram.cs
file - Added the previous
ipam
ip addresses to Blazor’sKnownProxies
and `KnownNetworks - Added the
real_ip_header
andset_real_ip_from
in thenginx.config
as suggested by many answers I found on Google - 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 thenginx.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.
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
In your
docker-compose.yml
, you’ve usedipam
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 theKnownProxies
. In thenginx.conf
, you have multiple redundant lines likeproxy_set_header X-Real-IP $remote_addr;
.Remove all known proxies and networks except the Docker subnet.
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.For debugging purpose, try and create a custom middleware in your Blazor application to log the values of the
X-Real-IP
andX-Forwarded-For
headers. That way, you can check if these headers are reaching your Blazor application with the correct values.In
Program.cs
, aftervar app = builder.Build();
, insert the custom middleware 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
andX-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.