共计 3037 个字符,预计需要花费 8 分钟才能阅读完成。
今天在尝试把自己写的博客软件使用 docker 部署到服务器中的时候出现了一个问题. 博客后台使用的 ASP.NET Core Blazor 服务器渲染模式, 在razor页面中使用HttpClient请求数据,服务器已经配置了https我希望使用 http2访问.初始化代码如下;
@inject Blogifier.Core.Api.CustomHttpClient HttpClient
@{
AppSettings.SiteBaseUrl = $"{Request.Scheme}://{Request.Host}";
AppSettings.SiteRoot = Url.Content("~/");
HttpClient.BaseAddress = new Uri($"{AppSettings.SiteBaseUrl}{AppSettings.SiteRoot}api/");
Layout = null;
}
在服务器渲染中我选择用当前请求体的信息得到api服务器的地址信息,在本地测试的时候都没有问题,结果放在服务器上 Scheme 获取到始终为 http;
尝试阅读的微软的官方文档 使用 Nginx 在 Linux 上托管 ASP.NET Core添加了配置
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
server {
listen 80;
listen 443 ssl http2;
server_name {hostname};
ssl_certificate /etc/nginx/sslcrt/{hostname}.pem;
ssl_certificate_key /etc/nginx/sslcrt/{hostname}.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://{dockeranme};
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 32 4k;
}
}
version: '3.1'
services:
niginx:
container_name: server_niginx
tty: true
image: nginx:latest
restart: always
ports:
- '443:443'
- '80:80'
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/sslcrt/:/etc/nginx/sslcrt/
environment:
TZ : 'Asia/Shanghai'
depends_on:
- blog
blog:
container_name: server_blog
restart: always
image: blog
environment:
TZ : 'Asia/Shanghai'
发现问题
反复尝试修改nginx的配置并且打印了 asp.net core 收到的header 确认包含X-Forwarded-For,X-Forwarded-Proto 但是问题依旧开始查看 asp.net core的源代码找到最终实现为 aspnetcore ForwardedHeadersMiddleware src ForwardedHeadersMiddleware的中间件,发现了关键代码
var checkKnownIps = _options.KnownNetworks.Count > 0 || _options.KnownProxies.Count > 0;
...
// For the first instance, allow remoteIp to be null for servers that don't support it natively.
if (currentValues.RemoteIpAndPort != null && checkKnownIps && !CheckKnownAddress(currentValues.RemoteIpAndPort.Address))
{
// Stop at the first unknown remote IP, but still apply changes processed so far.
_logger.LogDebug(1, "Unknown proxy: {RemoteIpAndPort}", currentValues.RemoteIpAndPort);
break;
}
这里会判断当前代理访问的ip地址是否存在于 KnownNetworks,KnownProxies中 并且KnownNetworks和KnownProxies 默认是有一个初始值的为本地地址 127.0.0.1,:::1;
最终发现问题 采用docker-compose部署 默认的容器内网地址是 172.18… 开启详细日志 中间件也会发送 Unknown proxy的日志;
解决问题
最终在 Startup.cs 添加如下代码问题解决
// 允许内网代理
services.Configure<ForwardedHeadersOptions>(options =>
{
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("172.18.0.0"), 16));
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
...
app.UseForwardedHeaders();
总结
在使用nginx反向代理的时候 UseForwardedHeaders 使用时必须注意代理的地址 且必须加入到 KnownNetworks,KnownProxies中 UseForwardedHeaders才会生效; 最无语的是 KnownNetworks,KnownProxies中默认是有值的, 也就是必须是本地地址才会生效,或许官方也是为安全考虑, 折腾了好久…