引言

最近在折腾统一认证中心,看到开源项目[IdentityServer4.Admin:https://github.com/skoruba/IdentityServer4.Admin]集成了IdentityServer4和管理面板,就直接拿过来用了。在尝试Nginx部署时遇到了诸如虚拟目录映射,请求头超长、基础路径映射有误等问题,简单记录,以供后人参考。

Nginx 配置路由转发

首先来看下[IdentityServer4.Admin:https://github.com/skoruba/IdentityServer4.Admin]的项目结构:

IdentityServer4.Admin /
├── Id4.Admin.Api                  # 用于提供访问Id4资源的WebApi项目
├── Id4.Admin                      # 用于提供管理Id4资源的Web管理面板
├── Id4.STS.Identity               # 用于提供 STS 服务的Web项目

作为三个独立的项目,分开部署很简单,但为了统一入口管理,我倾向于将 Id4.AdminId4.STS.Identity 部署在一个域名之下, Id4.Admin.API项目部署到网关中去。也就是通过 http://auth.xxx.com访问 Id4.STS.Identity,通过 http://auth.xxx.com/admin访问 Id4.Admin

这也就是遇到的第一个问题如何借助Nginx实现单域名多站点部署!

Kestrel作为一个边缘web服务器部署时,其将独占一个IP和端口。在没有反向代理服务器的情况下,用作边缘服务器的Kestrel不支持在多个进程之间共享相同的IP和端口。当将Kestrel配置为在端口上侦听时,Kestrel将处理该端口的所有网络通信,并且忽略请求头中指定的 Host请求头,也就意味着Kestrel 不会负责请求转发。

因此为了进行端口共享,我们需借助反向代理将唯一的IP和端口上将请求转发给Kestrel。也就是下面这张图。

根据Nginx 官方配置文档,通过配置Location就可以实现指定路径路由转发。

server {listen 80;listen [::]:80;server_name mysite;location / {proxy_pass http://id4.sts.identity:80;proxy_set_header Host $host;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}location /admin/ {proxy_pass http://id4.admin:80/;proxy_set_header Host $host;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}
}

我们 比较下两个proxy_pass的配置:

  1. location / { proxy_pass http://id4.sts.identity:80; }

  2. location /admin/ { proxy_pass http://id4.admin:80/; }

主要的不同点是 location/admin/ 节点下 proxy_pass http://id4.admin:80/结尾包含一个左斜杠 /。(如果没有这个左斜杠,所有的请求都会被路由到根节点。)比如有个请求 http://auth.xxx.com/admin/dashboard,那么nginx根据以上配置会将请求路由到 http://id4.admin:80/dashboard。也就是最后一个左斜杠会将替换掉 location 指定的路由规则,也就是这里的 /admin

但这样就OK了吗?Absolutely no!执行 nginx-s reload 你将会得到一个大大的 404

启用 UsePathBase 中间件

这时就要用到UsePathBase中间件了,其作用就是设置站点请求基础路径。在Web项目中添加 UsePathBase 中间件很简单,首先在 appsettings.json中添加一个配置项 PATHBASE,然后Startup的Config中启用就好。

public class Startup
{public Startup(IConfiguration configuration){Configuration = configuration;}private IConfiguration Configuration { get; }// ...public void Configure(...){// ...app.UsePathBase(Configuration.GetValue<string>("PATHBASE"));

启用 UseForwardedHeaders 中间件

使用反向代理还有一个问题要注意,那就是反向代理会模糊一些请求信息:

  1. 通过HTTP代理HTTPS请求时,原始传输协议(HTTPS)丢失,必须在请求头中转发。

  2. 由于应用程序是从代理服务器收到请求的,而不是真正的请求来源,因此原始客户端IP地址也必须在请求头中转发。

这也就是为什么上面的Nginx 配置,会默认包含以下两项配置的原因。

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

Nginx已经默认配置转发了以上信息,那么自然要显式告知ASP.NET Core Web 应用要从请求头中取回真实的请求信息。配置很简单,需要安`[Microsoft.AspNetCore.HttpOverrides:https://www.nuget.org/packages/Microsoft.AspNetCore.HttpOverrides/] NuGet包,然后在Startup的Config中启用中间件。

public class Startup
{public Startup(IConfiguration configuration){Configuration = configuration;}private IConfiguration Configuration { get; }// ...public void Configure(...){// ...app.UseForwardedHeaders(new ForwardedHeadersOptions{ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto });app.UsePathBase(Configuration.GetValue<string>("PATHBASE"));

有一点必须注意,依赖于传输协议的任何组件,例如身份验证,链接生成,重定向和地理位置,都必须在请求头转发中间件之后启用。通常,除了诊断和错误处理中间件外,请求头转发中间件应先于其他中间件运行。

配置完成后,重新部署,对于一般的项目,应该可以正常运行了。但也可能遭遇:

解除Nginx请求头转发大小限制

针对这种错误当然要查Nginx错误日志了,如果Nginx服务器部署在Linux服务器,那么默认日志文件在 /var/log/nginx/error.log,日志如下:17677925 upstream sent too big header while reading response header from upstream。简单翻译就是请求头数据过大。那我们就来看看转发的请求头到底会有多大,从下图来看请求头中携带的Cookie最大的有3K多。

nginx添加下面的配置即可:

proxy_buffer_size          128k;
proxy_buffers              4 256k;
proxy_busy_buffers_size    256k;

重新加载Nginx 配置,访问成功。

Is All Set? No!

修复基础路径错误

当我尝试点击Admin管理面板的链接时,得到无情的404,因为链接地址为:http://auth.xxx.com/configruaion/clients,正确的链接地址应该是 http://auth.xxx.com/admin/configruaion/clients。也就是Razor TagHelper 渲染的 <aasp-controller="Configruaion"asp-action="Clients">Manage Client</a>,并没有帮按照 UsePathBase指定的路径生成a标签链接。咱们只能看看源码一探究竟了[Microsoft.AspNetCore.Mvc.TagHelpers/AnchorTagHelper.cs:https://github.com/aspnet/Mvc/blob/master/src/Microsoft.AspNetCore.Mvc.TagHelpers/AnchorTagHelper.cs],最终在拼接 Herf属性时使用的是 varpathBase=ActionContext.HttpContext.Request.PathBase;来拼接基础路径。也就是说说TagHelper根据Http请求上下文中获取基础路径。因此如果采用 location/admin/{proxy_pass http://id4.admin:80/;这种路由映射,最终会丢失原始路由的基础路径,也就是 /admin/ 路由部分。所以,我们还是乖乖把基础路径补充上,也就是 proxy_pass http://id4.admin:80/admin/;至此完成反向代理的单域名多站点部署。

最后

一波三折,但最终不负期望。最后完整Nginx配置放出,以供参考:

server {listen 80;listen [::]:80;server_name mysite;location / {proxy_pass http://id4.sts.identity:80;proxy_set_header Host $host;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}location /admin/ {proxy_pass http://id4.admin:80/admin/;proxy_set_header Host $host;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;proxy_buffer_size          128k;proxy_buffers              4 256k;proxy_busy_buffers_size    256k;}
}

参考资料:

  1. [Configure ASP.NET Core to work with proxy servers and load balancers:https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-3.1]

  2. [GitHub Issue: Deploy to subdirectory #15464:https://github.com/dotnet/AspNetCore.Docs/issues/15464]

  3. [ASP.Net Core 3 App Running under a Subdirectory on Nginx:http://www.endycahyono.com/article/aspnetcore3-running-under-subdirectory-on-nginx]

ASP.NET Core 反向代理部署知多少相关推荐

  1. 使用Helm将ASP.NET Core应用程序部署到Kubernetes容器集群

    在<容器化单页面应用中RESTful API的访问>以及<容器化单页面应用中Nginx反向代理与Kubernetes部署>两篇文章中,我介绍了一套容器化ASP.NET Core ...

  2. Asp.Net Core 发布和部署(Linux + Jexus )

    前言 在上篇文章中,主要介绍了 Dotnet Core Run 命令,这篇文章主要是讲解如何在 asp.net core 中对我们的已经完成的程序进行发布和部署. 有关如何使用 Nginx 进行部署, ...

  3. Asp.Net Core 发布和部署( MacOS + Linux + Nginx )

    前言 在上篇文章中,主要介绍了 Dotnet Core Run 命令,这篇文章主要是讲解如何在Linux中,对 Asp.Net Core 的程序进行发布和部署. 有关如何在 Jexus 中进行部署,请 ...

  4. asp网上书店的代码_使用Helm将ASP.NET Core应用程序部署到Kubernetes容器集群

    在<容器化单页面应用中RESTful API的访问>以及<容器化单页面应用中Nginx反向代理与Kubernetes部署>两篇文章中,我介绍了一套容器化ASP.NET Core ...

  5. ASP.NET Core开发-Docker部署运行

    ASP.NET Core开发Docker部署,.NET Core支持Docker 部署运行.我们将ASP.NET Core 部署在Docker 上运行. 大家可能都见识过Docker ,今天我们就详细 ...

  6. ASP.NET Core开发Docker部署

    ASP.NET Core开发Docker部署,.NET Core支持Docker 部署运行.我们将ASP.NET Core 部署在Docker 上运行. 大家可能都见识过Docker ,今天我们就详细 ...

  7. 浅析web应用防火墙的反向代理部署

    浅析web应用防火墙的反向代理部署 现在,随着互联网的发展,越来越多用户对于网络的安全要求越来越高,对于安全设备的部署模式也需要根据不同场景的业务需要来进行调整.有一些客户为了对内网用户也隐藏自己真实 ...

  8. .net5 Nginx 反向代理部署

    .net5 Nginx 反向代理部署 几个概念先了解一下 集群 多个服务器(或者软件)呢,都可以完整的完成一个业务 eg:一个业务呢有A,B,C三个流程,服务器甲可以完成A,B,C.服务器乙也可以完成 ...

  9. ASP.NET Core 托管和部署(一)【Kestrel】

    ASP.NET Core 中的 Kestrel Web 服务器实现 ASP.NET Core 中的 Kestrel Web 服务器实现 Kestrel 是一个跨平台的适用于 ASP.NET Core ...

最新文章

  1. phoenix 开发API系列(二)phoenix 各类 api 实现方式
  2. 看完后,我才明白 Redis 为什么默认 16 个数据库?
  3. Python3——类
  4. 版本控制软件Visual Source safe使用小结 (配合上文)
  5. Docker镜像常用命令(三)
  6. 单片机shell命令_单片机裸机下写一个自己的shell调试器
  7. [SDOI2011]计算器
  8. 收下这10个终身学习的资源号,Max你的工作效率
  9. c语言sinx幂级数展开,求幂级数展开式的方法
  10. npcap lookback adapter回环网卡是什么 它的作用是什么
  11. 多维数据运算(矩阵乘法)
  12. 晶振电路电容选取的计算方法
  13. mac sublime中文乱码问题解决
  14. Oracleji数据库、实例、用户、表空间、表之间的关系
  15. Saas与Paas、Laas服务模式了解
  16. 使用cppcheck检查代码
  17. 我的编程之路:「懒惰」是程序员最大的美德
  18. MCE | 神经元为胰腺癌细胞提供营养
  19. 小八——WebGL心路历程(1),从一个原生的webGL程序粗放认识webGL
  20. Android M新控件之FloatingActionButton,TextInputLayout,Snackbar,TabLayout的使用

热门文章

  1. 为什么一点onclick按钮就提交表单?
  2. Oracle9i卸载后再次安装,设置的SID相同出现“指定的SID在本机上已经存在。请指定一个不同的SID。”...
  3. Concurrent connection limit
  4. latex插入gif_如何将照片和GIF插入Google幻灯片
  5. java ReentrantLock 锁相关笔记
  6. zookeeper的单实例和伪集群部署
  7. js温故而知新11(AJAX)——学习廖雪峰的js教程
  8. 9 C++ Boost 多线程,线程同步
  9. 在Android NDK中使用OpenSSL
  10. 【原】python中文文本挖掘资料集合