In short
To host ASP.NET Core 10 on IIS, you need a Windows Server environment, the IIS role, the .NET 10 Hosting Bundle, a published ASP.NET Core app, and an IIS app pool configured with No Managed Code.
This guide shows the full deployment flow on a Raff Windows VM:
Browser → Windows Server → IIS → ASP.NET Core Module V2 → ASP.NET Core 10 app
If you are here for the .NET 10 Hosting Bundle, install it on the same Windows Server that will run your IIS site. The Hosting Bundle gives IIS the runtime components and ASP.NET Core Module V2 required to launch your app.

Need a Windows VM for ASP.NET Core and IIS?
Deploy a Raff Windows VM with NVMe storage, unmetered bandwidth, RDP access, and browser console support.
View Windows VM plans
Who this guide is for
You want to host an ASP.NET Core web app on Windows Server with IIS as the front-end web server. Common scenarios:
- A small business app, intranet, customer portal, or dashboard that needs to run on a single Windows Server
- An ASP.NET Core API behind IIS, where IIS handles HTTPS, static assets, and request routing while your app handles business logic
- Multiple ASP.NET Core sites on one server, each with their own IIS bindings and app pools
- Replacing an aging ASP.NET Framework deployment with a modern .NET 10 codebase
- Testing a Windows VM before moving an ASP.NET Core app into production
If you're hosting at scale with multiple servers, load balancers, or container orchestration, Kestrel behind a reverse proxy or a container-based architecture may be a better fit than a single IIS server. This guide is for the common single-server or small-cluster case where IIS gives you HTTPS termination, static asset serving, bindings, and process management in a familiar Windows Server environment.
What you'll need
- A Windows Server 2025 or Windows Server 2022 machine. This guide was tested on a Raff Windows VM.
- Local administrator access through RDP. See our RDP connection guide if you haven't connected before.
- An ASP.NET Core app to deploy. We'll create one as part of this walkthrough using
dotnet new webapp. - The .NET 10 Hosting Bundle installed on the server.
- Optional but recommended: a separate machine for building such as your laptop, a CI runner, or a build server. Production servers should usually host apps, not compile them.
- Estimated time: 30-45 minutes for a first deployment, and much faster for future deployments after the server is prepared.
For a small staging app, internal tool, dashboard, or low-traffic website, a smaller Windows VM can be enough. For production apps, multiple IIS sites, SQL Server on the same machine, or heavier workloads, choose more CPU, RAM, and NVMe storage.
What changed in .NET 10 / 2026
If you're coming from older guides written for .NET 6, 7, 8, or 9, three things are different:
- .NET 10 is the current LTS target for new deployments. LTS releases receive support for three years. For new production ASP.NET Core deployments, target .NET 10 unless you have a specific compatibility reason not to.
- The Hosting Bundle and SDK are different packages. The Hosting Bundle lets IIS run ASP.NET Core apps. The SDK is required for
dotnet new,dotnet build, anddotnet publish. - The app pool should be set to No Managed Code. ASP.NET Core does not run through the classic .NET Framework CLR app pool runtime. IIS uses ASP.NET Core Module V2 to start and host the app.
Step 1 — Install the Web Server (IIS) role
Open PowerShell as administrator on the Raff Server and run:
Install-WindowsFeature -Name ` Web-Server, ` Web-Common-Http, ` Web-Static-Content, ` Web-Default-Doc, ` Web-Dir-Browsing, ` Web-Http-Errors, ` Web-App-Dev, ` Web-Net-Ext45, ` Web-AppInit, ` Web-ISAPI-Ext, ` Web-ISAPI-Filter, ` Web-Health, ` Web-Http-Logging, ` Web-Performance, ` Web-Stat-Compression, ` Web-Security, ` Web-Filtering, ` Web-Mgmt-Tools, ` Web-Mgmt-Console ` -IncludeManagementTools
This installs the IIS parent role plus the modules ASP.NET Core needs, including Common HTTP, App Development, ISAPI filters/extensions for ANCM V2, request filtering, dynamic compression, logging, and the management console.
Verify:
Get-WindowsFeature -Name Web-Server | Format-Table Name, InstallState Get-Service -Name W3SVC, WAS | Format-Table Name, Status, StartType
You should see Web-Server: Installed, W3SVC: Running, and WAS: Running.
The Manual start type for WAS (Windows Process Activation Service) is normal. It is started on demand by IIS. Do not change it just because it says Manual.
Confirm IIS is serving requests by browsing http://localhost from Edge on the server:

If you see the multi-language "Internet Information Services" welcome page, IIS is alive.
Article finding from our test: Windows Server 2025 IIS install completed without requiring a reboot. Older Windows Server versions may sometimes prompt for one depending on installed roles and pending updates.
Step 2 — Install the .NET 10 Hosting Bundle
The Hosting Bundle is a single installer that puts down the pieces IIS needs to run ASP.NET Core apps:
- .NET Runtime — the runtime that runs managed .NET code
- ASP.NET Core Runtime — the ASP.NET Core framework runtime
- ASP.NET Core Module V2 — the IIS module that starts and routes requests to your ASP.NET Core app
The fastest way is winget:
winget install --id Microsoft.DotNet.HostingBundle.10 --silent --accept-source-agreements --accept-package-agreements
The exact patch version may be newer than the examples in this guide. That is normal. Install the latest available .NET 10 Hosting Bundle unless your app requires a specific patched runtime version.
If winget isn't available or you prefer a GUI install, download the bundle from Microsoft's official .NET 10 download page:
https://dotnet.microsoft.com/download/dotnet/10.0
Choose:
ASP.NET Core Runtime → Hosting Bundle
The filename is usually similar to:
dotnet-hosting-10.0.x-win.exe
Run the installer as administrator.
Important: install IIS before the Hosting Bundle
For the cleanest setup, install IIS first, then install the .NET 10 Hosting Bundle.
If the Hosting Bundle is installed before IIS, repair or run the Hosting Bundle installer again after IIS is installed so ASP.NET Core Module V2 is registered correctly with IIS.
This guide installs IIS first, then the Hosting Bundle, to avoid that problem.
Refresh PATH in your current PowerShell session
The Hosting Bundle adds C:\Program Files\dotnet\ to the Machine PATH, but your existing PowerShell session may not see it until you reopen the window.
You can refresh PATH manually:
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
This is a common gotcha. If your dotnet command says "not recognized" right after installing the bundle, this is usually why.
Verify the runtime is registered
dotnet --list-runtimes
You should see entries similar to:
Microsoft.AspNetCore.App 10.0.x [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 10.0.x [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Verify ANCM is registered with IIS
Import-Module WebAdministration Get-WebGlobalModule -Name "AspNetCoreModuleV2" | Format-Table Name, Image
Expected output:
Name Image ---- ----- AspNetCoreModuleV2 %ProgramFiles%\IIS\Asp.Net Core Module\V2\aspnetcorev2.dll
If this returns nothing, ASP.NET Core Module V2 is not registered correctly. Re-run or repair the Hosting Bundle installer as administrator.
The Hosting Bundle does not replace a Windows server
The .NET 10 Hosting Bundle gives IIS the runtime components required to run ASP.NET Core apps. It does not provide the server itself.
For a real deployment, you still need a Windows environment with:
- IIS installed
- RDP access
- enough CPU and RAM for the app
- firewall control
- storage for app files, logs, and uploads
- backups or snapshots
- a domain and HTTPS certificate for production
That is why many small teams, agencies, MSPs, and internal software teams deploy ASP.NET Core apps on a Windows VM: they get direct control over IIS, app pools, bindings, certificates, logs, and deployment folders without managing physical hardware.
Step 3 — Restart IIS
After the Hosting Bundle is installed, restart IIS:
iisreset
Expected output:
Internet services successfully stopped Internet services successfully restarted
On a fresh server, your app may work without this restart. But running iisreset removes uncertainty and ensures IIS loads the ASP.NET Core Module correctly.
If you have production apps already running on the server, schedule this carefully because iisreset briefly interrupts IIS-hosted sites.
Step 4 — Publish an ASP.NET Core app
Two paths are available. Pick whichever fits your workflow.
Path A — Build on the same server (dev/staging only)
This is convenient for a single-server test, but it is not the cleanest production pattern. Production servers should usually run apps, not compile them.
You'll need the .NET 10 SDK, which is separate from the Hosting Bundle:
winget install --id Microsoft.DotNet.SDK.10 --silent --accept-source-agreements --accept-package-agreements # Refresh PATH for the current session $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") # Verify SDK is available dotnet --list-sdks
You should see a .NET 10 SDK version.
Article finding from our test: This SDK-vs-runtime distinction is the number-one thing that trips up first-time IIS deployers. The Hosting Bundle has no SDK. If you try dotnet new or dotnet publish without an SDK, you'll see No .NET SDKs were found.
Now create and publish a sample app:
# Make a working folder New-Item -ItemType Directory -Path "C:\src\RaffSampleApp" -Force Set-Location "C:\src\RaffSampleApp" # Create a Razor Pages webapp targeting .NET 10 dotnet new webapp --framework net10.0 --name RaffSampleApp --output . # Publish to deployment folder (framework-dependent, win-x64) dotnet publish -c Release -o C:\publish\RaffSampleApp --runtime win-x64 --self-contained false
The first time you run any dotnet command after installing the SDK, you may see a welcome message and telemetry information. The template may also create an ASP.NET Core HTTPS development certificate. That development certificate is not the same as a production IIS certificate.
Path B — Build elsewhere, copy to server (production pattern)
This is the better production pattern. Build on a developer workstation, a CI/CD runner such as GitHub Actions, Azure DevOps, GitLab CI, or a dedicated build server. Then copy the published output to the Raff Server.
On your build machine:
# From your project directory dotnet publish -c Release -o C:\publish\YourApp --runtime win-x64 --self-contained false
Then transfer the published folder contents to your Raff Server.
Options:
- RDP file transfer — copy from your local machine and paste into the RDP session
robocopyover SMB if you have file-share access to the serverscpor SFTP if you have OpenSSH configured on the server- Git-based deploy —
git pullon the server, then publish locally if the SDK is installed - Object storage drop — upload from CI, then pull down on the server
Whichever method you use, the result is the same: your published files sit in a folder on the Windows Server, ready for IIS to point at.
Self-contained vs framework-dependent
We used:
--self-contained false
This is a framework-dependent publish. Your app uses the .NET 10 runtime installed on the server via the Hosting Bundle.
For most IIS deployments, framework-dependent publishing is the right default because:
- output is smaller
- runtime patching is easier
- multiple apps can share the installed runtime
- it works naturally with the Hosting Bundle
The alternative is:
dotnet publish -c Release -o C:\publish\YourApp --runtime win-x64 --self-contained true
A self-contained publish bundles the runtime with your app, making the output larger. It can be useful when you need to pin a specific runtime version per app, but for most Raff Windows VM deployments, framework-dependent publish plus the Hosting Bundle is simpler.
What gets published
After dotnet publish, the output folder contains files such as:
RaffSampleApp.exe— the launcher executable IIS will runRaffSampleApp.dll— the app codeRaffSampleApp.deps.jsonandRaffSampleApp.runtimeconfig.json— runtime configurationappsettings.jsonand environment-specific appsettings filesweb.config— auto-generated; tells IIS how to launch the app via ANCMwwwroot\— static files such as CSS, JavaScript, and images- static web asset files created by the ASP.NET Core build
What's in the auto-generated web.config?
<?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=".\RaffSampleApp.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" /> </system.webServer> </location> </configuration>
Key things in there:
modules="AspNetCoreModuleV2"— the IIS handler installed by the Hosting BundleprocessPath=".\RaffSampleApp.exe"— IIS launches the app executablehostingModel="inprocess"— the app runs inside the IIS worker processstdoutLogEnabled="false"— stdout logs are disabled by default<location path="." inheritInChildApplications="false">— prevents this app's config from leaking into nested child apps
You do not need to edit this file for the sample deployment. For real production apps, you may temporarily enable stdout logging during troubleshooting, or add custom headers, MIME types, and security rules as needed.

