ASP.NET Core Hosting Models in 2026: Kestrel vs IIS In-Process vs IIS Out-of-Process vs Nginx — Enterprise Decision Guide

Search for a command to run...

No comments yet. Be the first to comment.
Retrieval-Augmented Generation lives or dies on one unglamorous step, and it is not the model or the vector database. It is chunking. When you get chunking documents for RAG in .NET wrong, the model r

Most teams reach for caching the moment an API gets slow, wire up Redis or output caching, and move on. But there is an older, lighter mechanism built into HTTP itself that solves two problems at once

If you shipped an AI agent in .NET over the last two years, there is a good chance it runs on Semantic Kernel. That was the right call at the time. But with Microsoft Agent Framework reaching GA in Ap

The first time an AI feature I shipped went down in production, nothing in my code had changed. The model provider had a bad afternoon: a wave of 429 Too Many Requests, then a stretch of 503s, and eve

If you have tried to add OpenTelemetry.Extensions.Logging to a .NET project, you already know how this ends. The restore fails, NuGet tells you the package cannot be found, and you start second-guessi

Coding Droplets
297 posts
Coding Droplets is your go-to resource for .NET and ASP.NET Core development. Whether you're just starting out or building production systems, you'll find practical guides, real-world patterns, and clear explanations that actually make sense.
From beginner-friendly tutorials to advanced architecture decisions. We publish fresh .NET content every day to help you grow at every stage of your career.
Choosing the wrong ASP.NET Core hosting model in production is one of those decisions that seems trivial until it isn't. Teams routinely leave performance on the table, misconfigure reverse proxies, or build deployments that work fine in development and silently misbehave under load. Understanding which ASP.NET Core hosting model your team should use — and why — is a foundational architectural decision that affects throughput, security posture, deployment complexity, and operational cost.
🎁 Want implementation-ready .NET source code you can drop straight into your project? Join Coding Droplets on Patreon for exclusive tutorials, premium code samples, and early access to new content. 👉 https://www.patreon.com/CodingDroplets
ASP.NET Core ships with several hosting options, and the landscape has shifted meaningfully in 2026. Kestrel has matured into a production-grade edge server. IIS in-process hosting has become the default for Windows-based deployments. Nginx and other reverse proxies remain the standard for Linux and containerised workloads. This guide walks through each option, the trade-offs enterprise teams need to understand, and a decision matrix for selecting the right model for your environment.
ASP.NET Core hosting models define the relationship between the HTTP server that receives requests and the process that runs your application code. There are four practical configurations most teams encounter:
w3wp.exe). IIS handles the TCP connection and hands it directly to Kestrel's in-process variant.Each configuration makes different promises about performance, security, and operational footprint.
Kestrel has come a long way. In .NET 10, it supports HTTP/1.1, HTTP/2, and HTTP/3 (QUIC) natively, with TLS termination built in. For internal microservices, Azure-hosted APIs behind Azure Front Door or Application Gateway, and containerised workloads where the container orchestrator handles ingress, Kestrel alone is often the right answer.
Where Kestrel-only works well:
Where Kestrel-only creates risk:
If your application is internet-facing and you don't have a cloud-native edge layer in front of it, running Kestrel alone is not recommended for production. Put a reverse proxy in front of it.
IIS in-process hosting, introduced in ASP.NET Core 2.2 and made the default in 3.x and beyond, runs your application inside the IIS worker process using a variant of Kestrel called IISHttpServer. Requests never leave the process boundary — there is no loopback proxy hop.
The performance difference is meaningful. Microsoft's own benchmarks show that in-process hosting delivers significantly higher request throughput than out-of-process, precisely because requests don't travel over the loopback adapter.
When to use IIS in-process:
Limitations to understand:
w3wp.exeFor teams with existing Windows infrastructure, IIS in-process hosting is typically the right default. The performance gains over out-of-process are real, and the operational model is familiar to .NET developers who have worked with IIS for years.
Out-of-process hosting was the original hosting model for ASP.NET Core on IIS. Your app runs in a dedicated dotnet.exe process. IIS receives requests, hands them to the ASP.NET Core Module, which proxies them to Kestrel over the loopback adapter (HTTP on localhost).
The extra network hop introduces latency and reduces throughput compared to in-process. For most workloads, this difference is measurable under high load.
When out-of-process still makes sense:
The honest assessment: For the vast majority of new ASP.NET Core projects on Windows, in-process hosting is the better default. Out-of-process is a deliberate choice for specific operational or isolation requirements — not a default you should fall back to without a reason.
On Linux — whether bare metal, virtual machines, or containers — Kestrel behind Nginx (or another reverse proxy) is the most widely used production pattern. Nginx handles TLS termination, serves static files, performs request buffering, and can enforce connection limits. Kestrel handles the .NET application layer.
This is exactly how ASP.NET Core recommends deploying on Linux hosts. The separation of concerns is clean: the reverse proxy handles infrastructure-level concerns, and Kestrel handles application concerns.
Why a reverse proxy in front of Kestrel matters for production:
X-Forwarded-For, X-Forwarded-Proto) are standardised, ensuring your app sees correct client IP addresses and scheme informationCommon mistakes with this model:
ForwardedHeadersMiddleware in your ASP.NET Core pipeline — without it, your app sees Nginx's IP address as the client IP, which breaks IP-based rate limiting, geolocation, and loggingASPNETCORE_URLS to bind on all interfaces instead of localhost — your app should only accept connections from the reverse proxy, not directly from the internetAllowedHosts setting in appsettings.json, leaving the app open to host header injection attacksThe ASP.NET Core Zero to Production course covers the full deployment chapter — including how the hosting model, Nginx configuration, and ForwardedHeaders middleware fit together in a production-ready API pipeline.
HTTP.sys is a Windows-only server that sits at the kernel level, predating Kestrel. It supports Windows Authentication natively and can host multiple apps on the same port using the Windows HTTP Server API.
HTTP.sys is rarely the right choice for modern ASP.NET Core APIs. The main case for it is when you need Windows Authentication without IIS, or when you need kernel-level request filtering on Windows. Outside those scenarios, IIS in-process or Kestrel-behind-Nginx covers the requirements better.
In Kubernetes, your ASP.NET Core app runs in a container. The cluster provides ingress (NGINX Ingress Controller, Traefik, Istio, or Azure Application Gateway Ingress). Your pod typically only needs Kestrel — no IIS, no in-process hosting.
The hosting model for Kubernetes is therefore the simplest one: Kestrel bound to 0.0.0.0:8080 (non-root-friendly, no privileged ports), behind the cluster's ingress layer. TLS terminates at the ingress, not inside your pod.
The one thing teams consistently get wrong in Kubernetes deployments is not configuring graceful shutdown correctly. When the Kubernetes scheduler sends SIGTERM, your pod needs to finish in-flight requests before the container is killed. ASP.NET Core's IHostApplicationLifetime handles this, but only if your app is configured to respect it. Misconfigured shutdown handling leads to dropped requests during rolling updates.
| Deployment Target | Recommended Hosting Model | Reason |
|---|---|---|
| Windows + IIS (existing infra) | IIS In-Process | Best throughput, operational familiarity |
| Windows, needs process isolation | IIS Out-of-Process | Crash isolation, independent lifecycle |
| Linux / Ubuntu / Debian | Kestrel + Nginx (reverse proxy) | Standard Linux production pattern |
| Docker / Containers | Kestrel directly | Ingress handled by orchestrator |
| Kubernetes | Kestrel directly | Pod-level server, ingress at cluster layer |
| Azure App Service (Windows) | IIS In-Process | Default on App Service Windows stacks |
| Azure App Service (Linux) | Kestrel (managed) | App Service handles the edge layer |
| Internet-facing, no cloud edge | Kestrel + Nginx or IIS | Kestrel alone is insufficient for internet edge |
| Windows Authentication required | IIS In-Process or HTTP.sys | Kestrel cannot handle NTLM/Kerberos alone |
Mixing hosting models across environments: Running IIS in-process in production and Kestrel-only in development is acceptable because Kestrel behavior is consistent. But switching between in-process and out-of-process between environments introduces subtle differences in how the application initializes and how the host lifecycle works.
Not forwarding headers in reverse proxy deployments: Any Kestrel-behind-proxy setup requires explicit ForwardedHeadersMiddleware configuration. Teams that skip this end up logging 127.0.0.1 for every request and producing rate-limiting rules that are entirely ineffective.
Ignoring connection limits: Kestrel has default connection limits that are reasonable for most apps but need tuning for high-concurrency workloads. The KestrelServerOptions.Limits API lets you configure maximum connections, request body size, and concurrent upgrade requests. Teams that don't review these limits often discover them only when load tests reveal unexpected throttling.
Assuming IIS out-of-process is the same as in-process: They are not the same. Startup behavior, logging pipeline initialization, and application pool recycling interactions differ. Teams that migrate from out-of-process to in-process without reviewing the differences will encounter edge cases in production.
Binding to 0.0.0.0 when behind a proxy: Your app should only accept connections from localhost (or the internal proxy network) when running behind a reverse proxy. Binding to all interfaces exposes Kestrel's HTTP port to external traffic, bypassing the proxy entirely.
The hosting model directly affects your security surface:
For teams that handle sensitive data or operate in regulated environments, IIS in-process on Windows or a hardened Nginx reverse proxy on Linux is the more defensible choice over bare Kestrel.
☕ Prefer a one-time tip? Buy us a coffee — every bit helps keep the content coming!
What is the default hosting model in ASP.NET Core in 2026? When hosting on IIS, the default is in-process hosting since ASP.NET Core 3.x. For containerised and Linux deployments, Kestrel is the default server, typically running behind a reverse proxy at the infrastructure layer.
Is Kestrel production-ready for internet-facing APIs in 2026? Yes, when deployed behind a reverse proxy or cloud edge layer (Azure Front Door, AWS ALB, Cloudflare). Kestrel alone — directly internet-facing without a proxy — is not recommended because it lacks the hardened request filtering and security features of a dedicated web server. For APIs behind a cloud gateway, Kestrel-only is perfectly appropriate.
What is the performance difference between IIS in-process and out-of-process hosting? IIS in-process hosting eliminates the loopback proxy hop that out-of-process requires. In Microsoft's benchmarks, in-process delivers meaningfully higher request throughput. For most business APIs, the difference won't be the bottleneck, but for high-throughput workloads, in-process is the correct choice.
Should I use Kestrel with HTTP/3 in production? HTTP/3 (QUIC) support is available in Kestrel and has matured in .NET 9 and 10. It requires UDP support in your network stack and TLS 1.3. For teams on modern infrastructure with clients that support HTTP/3, enabling it can reduce latency for initial connections. For most enterprise APIs, HTTP/2 with Kestrel covers the majority of use cases without the additional configuration complexity.
What is ForwardedHeadersMiddleware and why is it critical?
ForwardedHeadersMiddleware tells ASP.NET Core to trust and parse X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Host headers set by an upstream reverse proxy. Without it, your application sees the proxy's IP as the client IP, and Request.Scheme will always report http even on HTTPS connections. This breaks IP-based rate limiting, geo-detection, security audit logs, and HTTPS redirects. Always configure it when running behind a proxy.
Can I use IIS in-process hosting in Docker containers? IIS does not run inside Linux containers. For Docker deployments, Kestrel is the correct server. On Windows containers, IIS in-process is technically possible but adds container size and complexity — most teams use Kestrel in containers on both Windows and Linux for consistency.
What about HTTP.sys — should my team consider it? HTTP.sys is worth evaluating only if you specifically need Windows Authentication without IIS (for scenarios like internal tools on an intranet), or if you need kernel-level request filtering on Windows. For standard public APIs, IIS in-process or Kestrel-behind-Nginx covers requirements better with less operational complexity.