Deploying ASP.NET Core applications on a Windows VPS presents several architecture decisions: whether to use IIS as a reverse proxy or run Kestrel standalone, how to configure application pools for optimal throughput, and which Windows Server version provides the best runtime characteristics. This guide compares deployment models and optimization strategies for ASP.NET Core on Windows VPS.
When selecting a host for ASP.NET Core workloads, compare Windows VPS plans based on CPU core count, RAM, and disk type — these directly affect ASP.NET Core application throughput and latency.
Deployment Model Comparison: IIS Reverse Proxy vs. Kestrel Standalone
ASP.NET Core can run behind IIS as a reverse proxy or as a standalone Kestrel process. Each approach has tradeoffs:
| Factor | IIS + ASP.NET Core Module (ANCM) | Kestrel Standalone |
|---|---|---|
| Setup complexity | Moderate — requires IIS, ANCM, app pool config | Low — run dotnet command, configure firewall |
| Process management | IIS manages lifetime, auto-restart, recycling | Requires external process manager (NSSM, Windows Service) |
| SSL termination | IIS handles HTTPS, certificates, HTTP/2 | Kestrel handles HTTPS directly or use a reverse proxy |
| CPU overhead | ~3-5% overhead from reverse proxy + ANCM | Minimal — direct Kestrel connection |
| Request queuing | IIS kernel-mode request queue | Kestrel in-process queue |
| Windows auth / AD integration | Native support via IIS | Requires middleware or NTLM fallback |
| Logging and monitoring | IIS logs, Event Viewer, App Pool metrics | Application logs, Performance counters only |
Recommendation: For most production ASP.NET Core deployments on a Windows VPS, the IIS + ANCM model is preferred. IIS provides battle-tested process management, SSL termination, and integration with Windows authentication. Use Kestrel standalone only for containerized deployments or when you need absolute minimum overhead with a custom process manager.
Step-by-Step: Deploying ASP.NET Core Behind IIS
1. Install the .NET Hosting Bundle on Windows Server
The .NET Hosting Bundle includes the .NET runtime, ASP.NET Core runtime, and the ASP.NET Core Module (ANCM) for IIS. Download the latest from dotnet.microsoft.com. After installation, verify the module is registered in IIS:
dotnet --list-runtimes
# Look for: Microsoft.AspNetCore.App x.x.x
2. Publish the Application
From your development machine, publish the application as a framework-dependent deployment:
dotnet publish -c Release -o ./publish
Copy the publish output to your Windows VPS using RDP, FTP, or robocopy.
3. Create an IIS Application Pool
ASP.NET Core applications require an application pool configured with No Managed Code (.NET CLR version), because the runtime is handled by ANCM, not the IIS classic pipeline:
- Open IIS Manager → Application Pools → Add Application Pool
- Name it (e.g.,
MyAppPool) - Set .NET CLR version to No Managed Code
- Set Managed pipeline mode to Integrated
- Under Advanced Settings, set Idle Time-out (minutes) to 0 for production to prevent app pool shutdown
4. Create the IIS Website and Configure web.config
Create a new website pointing to the published folder and assign the application pool. The web.config file generated during publish should look like:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*"
modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet"
arguments=".\MyApp.dll"
stdoutLogEnabled="false"
stdoutLogFile=".\logs\stdout"
hostingModel="inprocess" />
</system.webServer>
</location>
</configuration>
Performance Optimization for ASP.NET Core on Windows VPS
Application Pool Tuning
| Setting | Default | Recommended | Rationale |
|---|---|---|---|
| Queue Length | 1000 | 5000 | Prevents request drops under burst traffic |
| Idle Time-out | 20 min | 0 (disabled) | Prevents cold starts on first request |
| Recycling → Fixed Intervals | 1740 min | 0 (disabled) | In-process hosting model means recycling kills the app; restart via app pool recycle on deployment instead |
| Private Memory Limit | Unlimited | Set per VPS RAM (e.g., 512 MB for 2 GB VPS) | Prevents runaway memory consumption |
| Rapid-Fail Protection | Enabled (5 failures/5 min) | Disabled for critical apps | In-process crashes are rare; rapid-fail can take the site offline unnecessarily |
Kestrel Configuration
Kestrel runs in-process with IIS via ANCM. Key configuration in appsettings.json or Program.cs:
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.MaxConcurrentConnections = 100;
options.Limits.MaxRequestBodySize = 104857600; // 100 MB
options.Limits.MinRequestBodyDataRate =
new MinDataRate(100, TimeSpan.FromSeconds(10));
options.Limits.MinResponseDataRate =
new MinDataRate(100, TimeSpan.FromSeconds(10));
});
In in-process hosting mode, Kestrel and IIS share the same process. Set MaxConcurrentConnections based on your VPS RAM — approximately 10–20 connections per 256 MB of available RAM is a safe baseline.
Response Caching and Compression
Enable response caching in IIS for static assets and compression for dynamic responses:
- IIS Output Caching feature — cache static file types (.css, .js, .png) for 1–24 hours
- Enable Static Compression and Dynamic Compression in IIS
- Add ASP.NET Core response caching middleware:
app.UseResponseCaching() - Configure
Cache-Controlheaders in your middleware pipeline
Database Connection Pooling
If your ASP.NET Core application connects to SQL Server or another database, configure connection pooling in the connection string:
"ConnectionStrings:DefaultConnection": "Server=localhost;Database=MyAppDb;User Id=sa;Password=***;Pooling=True;Min Pool Size=5;Max Pool Size=100;Connection Lifetime=300;"
Set Min Pool Size to 5–10 to avoid connection creation overhead on first request. Set Max Pool Size based on your application pool queue length — typically 100–200 for a 2–4 GB VPS.
VPS Sizing for ASP.NET Core Workloads
The required VPS resources depend on application complexity and expected traffic. Measured benchmarks for a typical ASP.NET Core MVC application:
| Application Type | Recommended VPS Spec | Estimated Requests/sec | RAM Usage (idle/loaded) |
|---|---|---|---|
| Simple API (5-10 endpoints) | 1 vCPU, 1 GB RAM | 500-1500 | 80 MB / 200 MB |
| MVC web app with database | 2 vCPU, 2 GB RAM | 1000-3000 | 150 MB / 400 MB |
| Heavy data processing app | 4 vCPU, 4 GB RAM | 2000-5000 | 300 MB / 1 GB |
| High-traffic SaaS platform | 4-8 vCPU, 8 GB RAM | 5000+ | 500 MB / 2 GB |
Monitoring and Diagnostics
Enable these monitoring tools on your Windows VPS for ASP.NET Core:
- IIS Failed Request Tracing (FREB) — capture full request/response details for 500 errors
- dotnet-counters — real-time performance counters:
dotnet tool install -g dotnet-counters - dotnet-dump — memory dump analysis for memory leaks
- Windows Performance Recorder — CPU profiling and thread analysis
- Application Insights or OpenTelemetry — distributed tracing and telemetry
Conclusion: IIS vs. Kestrel for ASP.NET Core on Windows VPS
For the vast majority of ASP.NET Core deployments on a Windows VPS, the IIS in-process hosting model is the right choice. It provides process management, SSL termination, logging, and integration with Windows auth without meaningful performance overhead. Kestrel standalone is appropriate for specialized cases — Docker containers, microservice architectures, or environments where IIS is not available.
When planning your deployment, select a Windows VPS with at least 2 vCPU cores and 2 GB RAM for a smooth development-to-production pipeline. Compare Windows VPS plans and pricing to find a host that meets your ASP.NET Core workload requirements.