:root{--puock-block-not-tran:100%}

ASP.NET Core中的Docker部署:解决转接头中间件问题

613次阅读
没有评论

共计 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中默认是有值的, 也就是必须是本地地址才会生效,或许官方也是为安全考虑, 折腾了好久…

正文完
 2
太阳
版权声明:本站原创文章,由 太阳 于2021-01-28发表,共计3037字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)