Docker中Nginx反向代理Dotnet项目出现连接拒绝错误求助
问题描述
将.NET项目部署在Nginx反向代理后,直接通过docker run -p 8081:8081访问项目运行正常,但通过Nginx访问时,容器内的.NET项目会尝试使用外部URL访问自身,抛出System.Net.Http.HttpRequestException: Connection refused错误。
Nginx配置
server { listen 443 ssl http2; server_name asvbr; ssl_protocols TLSv1.2 TLSv1.3; ssl_certificate /etc/nginx/cert.pem; ssl_certificate_key /etc/nginx/cert.key; underscores_in_headers on; large_client_header_buffers 4 32k; location / { resolver 127.0.0.11 ipv6=off valid=30s; # 禁用缓存 add_header Last-Modified $date_gmt; add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; if_modified_since off; expires off; etag off; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Connection "Upgrade"; proxy_set_header host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Proto $scheme; set $asvbr_backend_servers asv-br_asv-br; proxy_pass http://$asvbr_backend_servers:8081; } }
控制台报错信息
[2023-05-04T13:46:33.259Z] Information: Normalizing '_blazor' to 'https://asvbr/_blazor'. blazor.server.js:1 [2023-05-04T13:46:33.315Z] Information: WebSocket connected to wss://asvbr/_blazor?id=Hv-fSHSk_-dobtiI41vOqQ. blazor.server.js:21 [2023-05-04T13:46:33.342Z] Error: System.Net.Http.HttpRequestException: Connection refused (asvbr:443) ---> System.Net.Sockets.SocketException (111): Connection refused at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken) at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token) at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|283_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
网络抓包情况
在.NET容器内抓取网络包后发现,项目会尝试通过用户侧网络经Nginx访问自身。
解决方案
问题根源是.NET应用未正确识别反向代理后的真实外部地址,导致内部请求错误指向外部域名,而容器内部无法访问该外部域名的443端口。以下是具体解决步骤:
1. 完善Nginx转发头配置
在Nginx的location /块中补充X-Forwarded-Port头,确保端口信息正确传递:
proxy_set_header X-Forwarded-Port $server_port;
2. 配置.NET应用识别反向代理头
需要告诉.NET应用它运行在反向代理之后,使用转发头构建正确的URL。
方式一:代码中配置(Program.cs)
在注册服务前添加转发头配置:
builder.Services.Configure<ForwardedHeadersOptions>(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost; // 添加Nginx容器的IP或子网到可信代理列表,比如Docker默认子网172.17.0.0/16 options.KnownProxies.Add(IPAddress.Parse("172.17.0.0/16")); });
然后在app.UseRouting()之前启用转发头:
app.UseForwardedHeaders();
方式二:环境变量配置
给.NET容器设置环境变量,自动启用转发头处理:
ASPNETCORE_FORWARDEDHEADERS_ENABLED=true # 可选:指定可信代理 ASPNETCORE_KNOWNPROXIES="172.17.0.0/16"
3. 针对Blazor Server的额外配置(如果是Blazor项目)
Blazor Server需要正确的外部URL来处理SignalR连接和内部请求,可以通过以下方式指定:
代码配置(Program.cs)
builder.WebHost.UseUrls("http://0.0.0.0:8081"); // 容器内监听地址 builder.Services.AddServerSideBlazor() .AddHubOptions(options => { options.ClientTimeoutInterval = TimeSpan.FromSeconds(30); }); // 配置HTTPS端口 builder.Services.Configure<MvcOptions>(options => { options.SslPort = 443; options.Filters.Add(new RequireHttpsAttribute()); });
环境变量配置
ASPNETCORE_URLS="http://0.0.0.0:8081" ASPNETCORE_SSL_PORT=443 ASPNETCORE_FORWARDEDHEADERS_ENABLED=true
4. 确保Docker网络连通性
确认Nginx和.NET容器处于同一个Docker网络中,容器可以通过服务名(如asv-br_asv-br)访问对方的8081端口,避免内部请求走外部网络。
验证
修改配置后重启Nginx和.NET容器,通过Nginx访问应用,检查控制台是否还有连接拒绝错误。同时可以在.NET应用中输出HttpContext.Request.Host和HttpContext.Request.Scheme,确认是否正确获取到asvbr和https。
内容的提问来源于stack exchange,提问作者Alexander Abramov

