Deploy ASP.NET Core to IIS with Plesk for Windows: Complete Walkthrough

You've built your ASP.NET Core app, it runs locally, and you've signed up for a Windows hosting plan with Plesk. Now you need to actually deploy it. This is the complete walkthrough — from dotnet publish through site creation in Plesk through verifying your first production request — specifically for ASP.NET Core 8 LTS and ASP.NET Core 10 LTS on Adaptive Web Hosting. If you're new to Windows hosting or new to Plesk, this is the soup-to-nuts guide that gets you from dotnet new to live.

Before you start: what you need

An ASP.NET Core app targeting net8.0 or net10.0 (other LTS versions work the same way)

An Adaptive Web Hosting plan — any tier; the deployment process is identical from Developer ($9.49) up

Your Plesk login credentials, sent when you signed up

Either the .NET SDK installed locally (for dotnet publish) OR Visual Studio 2022 with the ASP.NET Core workload

An optional FTP client (FileZilla, WinSCP) if you prefer FTP over Web Deploy

What's already on the host (you don't need to install any of these):

Windows Server 2022 with IIS 10

.NET 8 LTS and .NET 10 LTS runtimes (side-by-side) plus the ASP.NET Core Module

SQL Server 2022 instance ready for your databases

Plesk for Windows with the .NET Toolkit installed

Let's Encrypt SSL extension for free auto-renewing certificates

Step 1 — publish your app locally

From your project's solution root, publish for production:

dotnet publish -c Release -o ./publish-output

This produces a folder containing:

YourApp.dll — the compiled application

YourApp.deps.json, YourApp.runtimeconfig.json — runtime metadata

web.config — IIS configuration (auto-generated; safe to leave alone)

appsettings.json + any environment-specific files

A wwwroot/ folder with static assets

All NuGet dependencies as DLLs

The resulting folder is typically 10-100 MB depending on dependencies. This is exactly what gets uploaded.

What about self-contained publishes?

You can use dotnet publish -c Release --self-contained -r win-x64 to include the entire .NET runtime in your publish output. Don't do this for typical IIS hosting — Adaptive's servers already have .NET 8 LTS and .NET 10 LTS installed system-wide, and a framework-dependent publish is 5-10x smaller. Self-contained is for cases where the host doesn't have your runtime version, which isn't applicable here.

Step 2 — log in to Plesk

Plesk is the control panel UI for IIS, SSL, databases, DNS, and email on your hosting plan. From your signup email or our welcome email, you'll have:

Plesk URL — something like https://cp.adaptivewebhosting.com:8443

Username — the account name you chose

Password — sent via secure email or available in your billing portal

The first time you log in, Plesk shows your subscription summary with disk and bandwidth quotas, your assigned domain, and any pre-installed sample sites. Bookmark this URL — you'll come back to it for every deployment.

Step 3 — create or select your site in Plesk

From the Plesk dashboard sidebar, click Websites & Domains. You'll see the domain that was set up at signup (or a placeholder you can rename).

For each domain, Plesk creates a default file structure:

/httpdocs/ ← the IIS site root, where your app files live

/logs/ ← IIS request logs + ASP.NET Core stdout logs

/anon_ftp/ ← public FTP area (we don't use this for app deploy)

/cgi-bin/ ← unused for ASP.NET Core

For the rest of this walkthrough, /httpdocs/ is your deployment target.

Step 4 — configure the .NET runtime in Plesk

In the domain's settings, find the Dedicated IIS Application Pool section. This is the dedicated worker process for your site — on Adaptive Web Hosting plans, every domain gets its own pool by default; you don't share with neighbour tenants.

Enable Dedicated IIS Application Pool (already enabled on every plan)

For CLR Version, choose No Managed Code — counterintuitive, but correct for ASP.NET Core. .NET Core / .NET 5+ runs out-of-process or in-process via the ASP.NET Core Module, not via the classic CLR.

For Application Pool Pipeline Mode, leave as Integrated

Save

The "No Managed Code" setting is the most common stumble for first-time deployers. If you set it to .NET CLR v4.0, your app will start but produce strange behaviour (the classic ASP.NET pipeline tries to handle requests before the ASP.NET Core Module gets them). Set it to "No Managed Code" and you're done.

Step 5 — upload your publish output

You have three good options. Pick the one that matches your workflow.

Option A: Plesk File Manager (easiest for first deploy)

From your domain settings, click File Manager

Navigate to /httpdocs/

Delete any sample files Plesk created (typically index.html)

Click Upload and select the entire contents of your publish-output folder

For folders, zip the publish output first, upload the ZIP, then use Plesk's "Extract Files" action to unpack in place. This is significantly faster than uploading thousands of files individually.

Option B: FTP / FTPS (best for repeated deploys)

Plesk creates an FTP account that maps to /httpdocs/. From the FTP Access menu in domain settings, copy the FTP credentials. In FileZilla or WinSCP:

Host: your domain or the IP from your Plesk welcome email

Protocol: FTP over TLS (FTPS) — explicit on port 21

Username and password from Plesk

Drag-drop the contents of publish-output into the FTP root. For subsequent deploys, you can re-upload only the files that changed.

Option C: Web Deploy (best for CI/CD pipelines)

Web Deploy (MSDeploy) is the publish target Visual Studio uses by default. To enable it on Plesk:

In your domain's Web Hosting Access settings, enable Microsoft Web Deploy publishing

Plesk shows the Web Deploy publish URL (something like https://your.host:8172/msdeploy.axd)

In Visual Studio, right-click your project → Publish → New profile → Web Deploy

Enter the publish URL, site name (your domain), username, password

Once configured, every Visual Studio Publish builds, packages, and ships in one click. The same configuration works from GitHub Actions using the azure/webapps-deploy action or directly via MSDeploy CLI.

Step 6 — verify the web.config

ASP.NET Core's dotnet publish generates a web.config in your publish output. It tells IIS where to find your DLL and how to launch the ASP.NET Core Module. The auto-generated version usually works without changes. If you need to inspect it, it looks 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=".\YourApp.dll"

stdoutLogEnabled="false"

stdoutLogFile=".\logs\stdout"

hostingModel="inprocess" />

</system.webServer>

</location>

</configuration>

Two things to know:

hostingModel="inprocess" is correct for production. In-process is faster, lower latency, and recommended for almost all workloads. Out-of-process is for niche scenarios (32-bit native code requirements, IIS modules that need classic ASP.NET).

stdoutLogEnabled="false" is correct for production. Turn this to true only when actively diagnosing a startup failure — see our HTTP 500.30 troubleshooting guide for the diagnostic workflow.

Step 7 — configure your database connection

Your appsettings.json from local development typically references (localdb)\MSSQLLocalDB — the Visual Studio LocalDB. That won't work in production. You need to:

In Plesk, go to Databases for your domain → Add Database → MS SQL Server 2022

Name the database, create a user, set a strong password — Plesk generates credentials if you'd rather

Plesk shows the connection string format on the confirmation screen

In your deployed appsettings.Production.json (or via Plesk's environment variable settings), set:

{

"ConnectionStrings": {

"DefaultConnection": "Server=localhost;Database=YourDb;User Id=app_user;Password=...;Connect Timeout=30;Encrypt=true;TrustServerCertificate=false"

}

}

The Server=localhost works because SQL Server 2022 is co-located with your IIS site on the same machine on Adaptive plans. For SSL behaviour, Encrypt=true is the default in .NET 8+; we recommend keeping it explicit.

Step 8 — restart the IIS app pool

From your domain's settings in Plesk → Dedicated IIS Application Pool → Recycle. The worker shuts down, IIS reloads your published DLL, and the next request starts fresh.

You can also do this via FTP / Web Deploy — uploading a new web.config or a new App_Offline.htm triggers an auto-recycle. The recycle is your "deploy complete" signal.

Step 9 — configure SSL (free, automatic)

Every Adaptive Web Hosting plan includes free auto-renewing Let's Encrypt SSL via Plesk's built-in extension:

From your domain's Plesk dashboard, click SSL/TLS Certificates

Click Install on the Let's Encrypt section

Enter the email address that should receive renewal notifications

Check "Secure the www subdomain" if applicable

Click Get it free

Plesk handles the ACME challenge with Let's Encrypt automatically. The certificate provisions in 30-60 seconds. Renewal happens automatically every 60 days for as long as your hosting account is active.

Step 10 — first-request verification

Open your domain in a browser. Things that should be true:

The site loads over HTTPS

Your ASP.NET Core app renders — the homepage, your API root, whatever your entry point is

Browser DevTools shows server response headers like X-Powered-By: ASP.NET (you can hide this in Program.cs)

If you get an HTTP 500.30 error, the app crashed during startup. See our HTTP 500.30 troubleshooting article — enable stdout logging temporarily and read the real exception.

Setting up continuous deployment

For ongoing deploys, you have two clean patterns:

Pattern A: Visual Studio Publish

Once you've configured the Web Deploy profile in Step 5C, every push of a new build is one click in Visual Studio's Publish tab. Good for solo developers and small teams.

Pattern B: GitHub Actions

Add a workflow file at .github/workflows/deploy.yml:

name: Deploy to Adaptive Web Hosting

on:

push:

branches: [main]

jobs:

deploy:

runs-on: windows-latest

steps:

- uses: actions/checkout@v4

- uses: actions/setup-dotnet@v4

with:

dotnet-version: '10.0.x'

- run: dotnet publish -c Release -o ./publish

- name: Deploy via Web Deploy

run: |

msdeploy.exe -verb:sync

-source:contentPath=.\publish

-dest:contentPath=YourDomain,computerName='https://your.host:8172/msdeploy.axd?site=YourDomain',username='${{ secrets.WEBDEPLOY_USER }}',password='${{ secrets.WEBDEPLOY_PASSWORD }}',authtype='Basic'

Store the Web Deploy credentials as GitHub Actions secrets. Every push to main builds, publishes, and ships automatically.

Frequently asked questions

Do I need to install the .NET runtime on Adaptive's servers myself?

No. .NET 8 LTS and .NET 10 LTS are pre-installed and maintained on every plan. If you target either runtime in your TargetFramework, your published app will find what it needs. We add new LTS runtimes to every plan as Microsoft releases them.

Does the deployment cause downtime?

Brief — typically 5-15 seconds during app pool recycle. For zero-downtime deploys, you'd need multiple servers behind a load balancer with rolling updates, which is beyond what shared hosting plans typically provide. For most workloads the brief interruption is acceptable; if you need true zero-downtime, that's the use case for Azure App Service deployment slots or a similar managed service.

Can I run multiple ASP.NET Core apps on one plan?

Yes. Each domain (or subdomain) gets its own IIS site with its own dedicated application pool on Adaptive plans. Common pattern: main app at www.yoursite.com, API at api.yoursite.com, staging at staging.yoursite.com — all on the same hosting plan, in separate worker processes.

What if my app needs environment variables instead of appsettings.json?

Plesk's Apache & nginx Settings for the domain has an "Environment variables" section — well, actually for IIS the equivalent is in the Web.config settings or in IIS Manager via Plesk's IIS Manager extension. You can also set them directly via the IIS Application Pool's "Environment Variables" property, or pass them through your web.config's <environmentVariables> section.

How do I see my app's logs?

Plesk's Logs view (per domain) shows the IIS request logs and any ASP.NET Core stdout logs (when stdoutLogEnabled="true"). You can also FTP into /logs/ directly. For structured application logging, use Serilog or NLog to write to logs/app-{date}.log — Plesk's File Manager exposes those alongside IIS logs.

What's the best way to deploy database schema changes?

For Entity Framework Core, run migrations from the deploy pipeline:

dotnet ef database update --connection "Server=...;Database=...;User Id=...;Password=..."

From GitHub Actions, this runs as a post-deploy step after the file upload. Make sure the connection string used here has appropriate permissions (typically db_owner for the migration user).

Can I deploy a Blazor Server or Blazor WebAssembly app the same way?

Yes — the deployment process is identical. Blazor Server is just an ASP.NET Core app with SignalR; the same dotnet publish + IIS hosting works. Blazor WebAssembly is just static files plus an optional ASP.NET Core backend. See our Blazor hosting complete guide for the specifics.

Bottom line

Deploying ASP.NET Core to IIS via Plesk is a 10-step, ~30-minute process for first-time deployers, and 2-minutes-per-push after you've configured CI/CD. The only common stumble is the app pool's "Managed Code" setting (should be "No Managed Code" for ASP.NET Core, not "v4.0").

On Adaptive Web Hosting, every plan includes pre-installed .NET 8 LTS and .NET 10 LTS runtimes, dedicated IIS Application Pools per domain, real SQL Server 2022, free auto-renewing Let's Encrypt SSL, and 24/7 ticket support for the hosting-specific questions. Every plan also includes a 30-day money-back guarantee. View hosting plans, compare features, or talk to an ASP.NET expert.

Back to Blog