IIS 后面挂 Kestrel,这 3 个配置错了就 502

502 Bad Gateway------部署 ASP.NET Core 应用时最常见的报错。IIS 明明跑着,Kestrel 也明明跑着,但请求就是过不去。这篇文章讲三个最容易配错的地方,每个都能让你 502。

大家好,我是码农刚子。

先说清楚架构。

IIS 后面挂 Kestrel,本质是IIS 做反向代理。用户请求到 IIS,IIS 通过 ASP.NET Core Module(ANCM)把请求转发给 Kestrel,Kestrel 执行你的应用代码,响应原路返回。

这条链路上任何一个环节断了,IIS 就返回 502。而三个配置错了,链路必断。

01 ANCM 没装或版本不匹配

这是 502.5 的头号元凶。

ANCM = ASP.NET Core Module。它是 IIS 和 Kestrel 之间的桥梁------没有它,IIS 不知道怎么启动 dotnet 进程,也不知道怎么转发请求。

两种情况会出问题:

① 服务器上没装 ANCM------你部署了应用,IIS 找不到模块,直接 502.5。这在全新服务器上最常见,装了 IIS 但忘了装 .NET Core Hosting Bundle。

② 装了但版本不匹配------你的应用 target 是 .NET 8,服务器上只有 .NET 6 的 runtime。ANCM 启动 dotnet 进程时找不到对应的 runtime,进程立即崩溃,IIS 收到 502.5。

怎么查?看 Windows 事件查看器:

复制代码
应用程序日志 → 来源: IIS AspNetCore Module
错误: Could not find the assembly 'aspnetcorev2_outofprocess.dll'

看到这条就是模块没装对。

解法 :装 .NET Core Hosting Bundle (不是 SDK,是 Hosting Bundle)。它包含 ANCM + .NET Runtime,一条命令搞定。去微软官网下对应版本的 installer,装完 iisreset 一下。

⚠️ 坑中坑:升级 .NET 版本后,老版本的 ANCM 可能残留。检查 IIS 管理器 → 模块 → 看是否有重复的 AspNetCoreModuleV2,清理掉旧版本。

02 web.config 的 hostingModel 配错

这是最容易迷的坑,因为两种托管模式的配置完全不同。

ASP.NET Core 在 IIS 里有两种托管模式:

InProcess------不启动独立 Kestrel 进程,ANCM 直接在 IIS 工作进程(w3wp.exe)内托管应用。性能最好,但你的代码跑在 IIS 进程里。

OutOfProcess------ANCM 启动独立的 dotnet 进程(Kestrel),IIS 做反向代理转发请求。隔离性更好,但多一层转发开销。

配错的典型场景:你以为用的是 OutOfProcess,但 web.config 写了 InProcess,结果 ANCM 试图在进程内托管,但你的 Program.cs 里配了 Kestrel 特有的设置(比如 ListenUnixSocket),启动直接崩。

web.config 长这样:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*"
           modules="AspNetCoreModuleV2"
           resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath="dotnet"
                arguments=".\MyApp.dll"
                hostingModel="inprocess"
                stdoutLogEnabled="true"
                stdoutLogFile=".\logs\stdout" />
  </system.webServer>
</configuration>

三个关键属性:

processPath------InProcess 模式下写 dotnet 或 .\MyApp.exe;OutOfProcess 模式下一样。但如果你的应用是 self-contained 部署,必须写 .\MyApp.exe,不能写 dotnet------因为服务器上可能没装 runtime。

arguments------framework-dependent 部署写 .\MyApp.dll;self-contained 不需要。

hostingModel------inprocess 或 outofprocess。.NET 6+ 默认 InProcess,但如果你显式写了 OutOfProcess,别又在 Program.cs 里用 IIS 专有 API。

💡 排查手段 :开启 stdout 日志------把 stdoutLogEnabled="true",确保 logs\stdout 目录存在且有 IIS 权限。502 时去看这个日志,启动错误信息全在里面。

03 请求转发超时和大小限制不一致

这个坑最阴------不是启动就 502,而是跑着跑着偶发 502。用户上传大文件时 502,或者长耗时接口偶发 502,其他请求正常。

原因是 IIS 和 Kestrel 各有各的限制,两层没对齐。

① 请求超时

IIS 侧:web.config 里 <aspNetCore requestTimeout="00:02:00" /> 默认 2 分钟。超了 IIS 直接断连,返回 502。

Kestrel 侧:KestrelServerOptions.Limits.KeepAliveTimeout 默认 130 秒。如果 IIS 的 requestTimeout 比 Kestrel 的 KeepAliveTimeout 长,会出现 IIS 还在等、Kestrel 已经关连接的情况------502。

对齐原则 :IIS 的 requestTimeout 必须小于 Kestrel 的 KeepAliveTimeout。留 10-20 秒余量。

② 请求体大小限制

IIS 侧:<requestLimits maxAllowedContentLength="30000000" />(约 28.6MB),在 system.webServer/security/requestFiltering 里配。

Kestrel 侧:KestrelServerOptions.Limits.MaxRequestBodySize 默认 30MB(~28.6MB)。

看起来差不多?但如果你的接口需要上传 100MB 文件,两层都要改。只改 Kestrel 不改 IIS,IIS 先拦住返回 413;只改 IIS 不改 Kestrel,Kestrel 拒绝,IIS 收到错误返回 502。

配置示例:

xml 复制代码
<!-- IIS 侧:web.config -->
<security>
  <requestFiltering>
    <requestLimits maxAllowedContentLength="104857600" />
  </requestFiltering>
</security>

<aspNetCore requestTimeout="00:05:00" ... />
csharp 复制代码
// Kestrel 侧:Program.cs
builder.WebHost.ConfigureKestrel(opts =>
{
    opts.Limits.MaxRequestBodySize = 104_857_600; // 100MB
    opts.Limits.KeepAliveTimeout =
        TimeSpan.FromMinutes(6); // > IIS requestTimeout
});

💡 记住这条线 :IIS 的限制 < Kestrel 的限制。让 IIS 先拦住,不要让请求过了 IIS 才被 Kestrel 拒------那样 IIS 只能返回 502,日志还不好查。

还有第三个阴坑 :MaxRequestBufferSize。Kestrel 默认 1MB 的请求缓冲区,如果你的请求 header 超过 1MB(比如带了一个超长的 cookie 或 token),Kestrel 直接拒绝连接,IIS 返回 502.3。解法是显式调大:

csharp 复制代码
opts.Limits.MaxRequestBufferSize = null; // 不限制
opts.Limits.MaxRequestLineSize = 16_384; // 16KB

502 的排查,就三步: 看事件查看器 → 看 stdout 日志 → 对齐 IIS 和 Kestrel 的限制 日志在哪,问题就在哪。


收藏这篇,下次 502 不用猜。 三个配置对一遍,问题跑不掉。

关注 CSharp精选营,每周二四 get 能直接抄的 C# 实战。

阅读原文👉:IIS 后面挂 Kestrel,这 3 个配置错了就 502 - 码录集

相关推荐
鑫 源1 小时前
C#源码开源, 获取macOS 电池数据,包括iOS (xamarin开发)
c#·.net·xamarin
xiangcns2 天前
PDMS PiplineTool(三十)一堆小优化+一个彩蛋功能
.net·二次开发·pdms
EatFan2 天前
MCP 从概念到落地:Java(Spring AI Alibaba)与 .NET 双栈接入实操对比
java·人工智能·后端·spring·.net·java后端·mcp
CSharp精选营3 天前
.NET 面试必问的 8 道 GC 题,建议收藏
.net·面试题·gc·c#面试题
驰骋工作流4 天前
C#/.NET 开源BPM工作流引擎6大常用对比选型分析驰骋BPM驰骋低代码低代码工作流引擎
开源·c#·.net
淡海水5 天前
02-02-原理篇-分代GC
算法·unity·c#·游戏引擎·.net·gc
1-1=05 天前
.NET 依赖注入 续
.net
淡海水5 天前
02-03-原理篇-大对象堆
unity·c#·游戏引擎·.net·gc