Kestrel vs IIS — чем отличаются, как хостировать?
Варианты размещения
Kestrel
builder.WebHost.ConfigureKestrel(k =>
{
k.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10 МБ
k.Limits.MaxConcurrentConnections = 10_000;
k.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2);
k.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30); // защита от Slowloris
k.AddServerHeader = false; // не раскрывать "Server: Kestrel"
k.ListenAnyIP(8080); // HTTP
k.ListenAnyIP(8443, o =>
{
o.UseHttps("cert.pfx", builder.Configuration["CertPassword"]);
o.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
});
});{
"Kestrel": {
"Endpoints": {
"Http": { "Url": "http://0.0.0.0:8080" },
"Https": { "Url": "https://0.0.0.0:8443", "Certificate": { "Path": "cert.pfx", "Password": "..." } }
},
"Limits": { "MaxRequestBodySize": 10485760 }
}
}Адрес также задаётся переменными ASPNETCORE_URLS / ASPNETCORE_HTTP_PORTS (в официальных Docker-образах .NET 8+ по умолчанию порт 8080).
IIS
| In-process (по умолчанию) | Out-of-process | |
|---|---|---|
| Где выполняется приложение | Внутри рабочего процесса IIS w3wp.exe |
Отдельный процесс dotnet.exe с Kestrel |
| Сервер | IISHttpServer (не Kestrel) |
Kestrel |
| Производительность | Выше — нет лишнего сетевого перехода | Ниже — IIS проксирует по localhost |
| Приложений на пул | Одно | Несколько |
| Настройка | <AspNetCoreHostingModel>InProcess</...> в .csproj / web.config |
OutOfProcess |
IIS даёт Windows-специфичные возможности: Windows Authentication, управление пулами приложений, автоматический перезапуск, централизованное управление сертификатами, кэш статики на уровне ядра.
Reverse proxy: зачем и что настроить
Причины поставить прокси перед Kestrel:
- TLS-терминация и управление сертификатами в одном месте (Let's Encrypt, cert-manager).
- Балансировка между экземплярами, health checks, zero-downtime деплой.
- Защита: WAF, лимиты соединений, фильтрация, скрытие внутренней топологии.
- Раздача статики, сжатие, кэширование, несколько приложений на одном IP/порту 443.
Forwarded Headers
За прокси Kestrel видит соединение от прокси: RemoteIpAddress = IP прокси, Scheme = http. Последствия — неправильные ссылки редиректа (http://), UseHttpsRedirection зацикливается, rate limiting и логи работают по IP прокси.
builder.Services.Configure<ForwardedHeadersOptions>(o =>
{
o.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
o.KnownProxies.Add(IPAddress.Parse("10.0.0.2")); // доверять только своему прокси!
// или o.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
});
var app = builder.Build();
app.UseForwardedHeaders(); // одним из первых в конвейереПример Nginx
server {
listen 443 ssl http2;
server_name shop.example.com;
ssl_certificate /etc/ssl/shop.crt;
ssl_certificate_key /etc/ssl/shop.key;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # для WebSocket / SignalR
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}YARP — reverse proxy на .NET
YARP (Yet Another Reverse Proxy) — библиотека Microsoft для построения прокси и API-шлюзов на ASP.NET Core: маршрутизация из конфигурации, балансировка, health checks, трансформации запросов, аутентификация на шлюзе.
builder.Services.AddReverseProxy().LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
app.MapReverseProxy();Hosting: как запускается приложение
WebApplication.CreateBuilder создаёт Generic Host (IHost): конфигурация, логирование, DI, hosted services (Kestrel сам — один из них), обработка сигналов ОС (SIGTERM → graceful shutdown).
- Graceful shutdown: при остановке Kestrel перестаёт принимать новые соединения, ждёт завершения текущих запросов (
HostOptions.ShutdownTimeout, по умолчанию 30 с), вызываетStopAsyncу hosted services. - Как служба:
builder.Host.UseWindowsService()/UseSystemd().
Вопросы на засыпку
Можно ли выставлять Kestrel напрямую в интернет?
Да, с ASP.NET Core 2.1 Kestrel считается достаточно защищённым для edge-сервера. Но прокси всё равно часто используют ради TLS-управления, балансировки, WAF и нескольких сайтов на одном IP.
Почему in-process в IIS быстрее?
Нет второго HTTP-перехода: запрос обрабатывается в том же процессе без сериализации в HTTP и передачи по loopback. Разница заметна на большом количестве мелких запросов.
Что такое HTTP.sys?
Альтернативный серверу Kestrel веб-сервер только для Windows, основанный на драйвере ядра http.sys. Поддерживает Windows Authentication, port sharing, кэш ответов в ядре. Используется, когда нужен edge-сервер на Windows без IIS.
Как работает graceful shutdown в Kubernetes?
Kubernetes отправляет SIGTERM и одновременно убирает pod из Endpoints. Из-за задержки распространения несколько запросов ещё могут прийти — поэтому добавляют preStop-хук с небольшой паузой, а terminationGracePeriodSeconds делают больше ShutdownTimeout.
Итог
Kestrel — сердце ASP.NET Core, IIS и Nginx — возможные «фасады» перед ним. В контейнерах Kestrel слушает HTTP за Ingress-ом, на Windows-серверах — in-process в IIS. Главное при работе за прокси — правильно настроенные Forwarded Headers с доверием только своим прокси.