Reputation: 3548
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:
options.ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor;
flags and app.UseForwardedHeaders();
in the Blazor Program.cs
fileipam
ip addresses to Blazor's KnownProxies
and `KnownNetworksreal_ip_header
and set_real_ip_from
in the nginx.config
as suggested by many answers I found on Googleproxy_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 AddressBut 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!
Update 1
I added some middleware in the Blazor app as suggested in the comments to capture the request headers as fast as they arrive without further manipulation, and the IPs are wrong, they still reflect the nGinx container IP instead of the Client IP's localhost address
Upvotes: 2
Views: 846
Reputation: 12769
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.
Upvotes: 2