{"id":652,"date":"2026-08-18T23:12:55","date_gmt":"2026-08-18T23:12:55","guid":{"rendered":"https:\/\/windows-vps.org\/blog\/?p=652"},"modified":"2026-08-27T06:15:37","modified_gmt":"2026-08-27T06:15:37","slug":"iis-web-deploy-publish-aspnet-visual-studio","status":"publish","type":"post","link":"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/","title":{"rendered":"How to Publish .NET Apps from Visual Studio to IIS Using Web Deploy"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">FTP-based deployments are fragile. A dropped connection mid-upload, a missing <code>web.config<\/code>, or mismatched file permissions can take a site offline for minutes. Microsoft Web Deploy (MSDeploy) solves this by using a sync engine that understands IIS structure: it uploads only changed files, applies web.config transformations, and can take the application offline during the swap. This guide walks through setting up Web Deploy on a Windows VPS, configuring Visual Studio to publish via Web Deploy, and troubleshooting the most common errors.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Install Web Deploy on the Server<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Web Deploy is available as a standalone installer from Microsoft. On your Windows VPS, download and run the Web Deploy 4.0 MSI. When prompted, choose the <strong>Complete<\/strong> installation type. The Typical option installs only the client tool, but the Complete installation adds the handler service, which is required for remote publishing:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Verify the installation after setup\n&amp; \"$env:ProgramFilesIISMicrosoft Web Deploy V4msdeploy.exe\" -version\n\n# Expected output: \"Microsoft (R) Web Deployment Tool Version 4.x\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After installation, confirm that the Web Management Service (WMSvc) is running and set to Automatic start:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Get-Service WMSvc | Format-List Name, Status, StartType\n\n# If not running:\nSet-Service WMSvc -StartupType Automatic\nStart-Service WMSvc\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Configure Remote Management<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Open IIS Manager on the server. Select the server node in the left panel, then double-click <strong>Management Service<\/strong>. Enable remote management on port <strong>8172<\/strong> with HTTPS. If you do not have a certificate installed, IIS can generate a self-signed one for testing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, open the Windows Firewall to allow inbound traffic on port 8172:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>netsh advfirewall firewall add rule name=\"Web Deploy 8172\" dir=in action=allow `\n  protocol=TCP localport=8172\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Create a Dedicated Deploy User<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of handing out Windows Administrator credentials, create an IIS Manager user scoped to the specific web site. In IIS Manager:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Under the server node, double-click <strong>IIS Manager Users<\/strong> and create a new user (e.g., <code>webdeploy<\/code>).<\/li>\n<li>Navigate to your target site, double-click <strong>IIS Manager Permissions<\/strong>, and add the new user.<\/li>\n<li>Grant <strong>Content Management<\/strong> delegation so the user can read and write the site folder but nothing else.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Test the endpoint from your local workstation before setting up Visual Studio:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>msdeploy.exe -verb:dump `\n  -dest:computerName=\"https:\/\/yourserver:8172\/msdeploy.axd\",`\n        userName=\"webdeploy\",password=\"YourPassword\",authType=\"Basic\" `\n  -allowUntrusted\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Configure the Publish Profile in Visual Studio<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With the server ready, set up the publish profile in Visual Studio:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Right-click the project and select <strong>Publish<\/strong> \u2192 <strong>New profile<\/strong> \u2192 <strong>Web Deploy<\/strong>.<\/li>\n<li>Server: <code>https:\/\/yourserver:8172\/msdeploy.axd<\/code>.<\/li>\n<li>Site name: The exact name of the IIS site (e.g., <code>contoso<\/code>).<\/li>\n<li>User name and password: The IIS Manager user you created.<\/li>\n<li>Check <strong>Validate Connection<\/strong> to confirm everything works before the first deployment.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For clean builds, enable <strong>Remove additional files at destination<\/strong>. This deletes orphaned files from previous deployments. Disable it if users upload content to the site folder that should not be removed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use <strong>Web.config transforms<\/strong> to swap connection strings and app settings per environment. Add a <code>Web.Release.config<\/code> file to your project:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;!-- Web.Release.config --&gt;\n&lt;configuration xmlns:xdt=\"http:\/\/schemas.microsoft.com\/XML-Document-Transform\"&gt;\n  &lt;connectionStrings&gt;\n    &lt;add name=\"Default\"\n         connectionString=\"Server=.;Database=app;User ID=app;Password=***\"\n         xdt:Transform=\"SetAttributes\"\n         xdt:Locator=\"Match(name)\" \/&gt;\n  &lt;\/connectionStrings&gt;\n  &lt;appSettings&gt;\n    &lt;add key=\"Environment\" value=\"Production\"\n         xdt:Transform=\"SetAttributes\"\n         xdt:Locator=\"Match(key)\" \/&gt;\n  &lt;\/appSettings&gt;\n&lt;\/configuration&gt;\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Before the first real deploy, use Visual Studio\u2019s <strong>Preview<\/strong> step in the publish dialog. It lists every file that will be added, updated, or deleted without touching the server. A quick scan of the preview catches the classic mistakes: a missing <code>appsettings.json<\/code>, a stray <code>bin<\/code> folder, or a transform that dropped a connection string.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The 5 Most Common Errors and Their Fixes<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Error<\/th><th>Cause<\/th><th>Fix<\/th><\/tr><\/thead><tbody><tr><td>ERROR_USER_UNAUTHORIZED<\/td><td>IIS Manager user lacks delegation on the site<\/td><td>Grant <strong>Content Management<\/strong> in IIS Manager Permissions on the site node<\/td><\/tr><tr><td>ERROR_DESTINATION_NOT_REACHABLE<\/td><td>Port 8172 blocked or Management Service stopped<\/td><td>Open the firewall rule; verify WMSvc is running and set to Automatic<\/td><\/tr><tr><td>ERROR_INSUFFICIENT_ACCESS_TO_SITE_FOLDER<\/td><td>ACLs on the web root block the deploy identity<\/td><td>Grant the IIS Manager user or app pool identity <strong>Modify<\/strong> permission on the site folder via <code>icacls<\/code><\/td><\/tr><tr><td>ERROR_FILE_IN_USE<\/td><td><code>w3wp.exe<\/code> holds the old DLLs<\/td><td>Place <code>app_offline.htm<\/code> in the site root before syncing (Web Deploy removes it after)<\/td><\/tr><tr><td>500 on msdeploy.axd<\/td><td>Handler not installed<\/td><td>Re-run the Web Deploy installer and choose <strong>Complete<\/strong>; restart the Management Service<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The locked-file error is the most common on busy sites. The reliable pattern is to place an <code>app_offline.htm<\/code> file in the site root before publishing, then delete it after. IIS sees the file, unloads the app pool, and no process holds the files. For automated deployments, add <code>-enableRule:AppOffline<\/code> to the msdeploy command \u2014 it drops the file automatically before syncing and removes it afterward.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5: Automate with CI\/CD<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The Visual Studio publish profile is a wrapper around <code>msdeploy.exe<\/code>. Your build agent can use the same command directly:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>msdeploy.exe -verb:sync -source:package=\"artifactssite.zip\" `\n  -dest:auto,computerName=\"https:\/\/yourserver:8172\/msdeploy.axd\",`\n        userName=\"webdeploy\",password=\"***\",authType=\"Basic\" `\n  -setParam:name=\"IIS Web Application Name\",value=\"contoso\" `\n  -allowUntrusted -enableRule:AppOffline\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Store the password in your build agent\u2019s secret store, never in the repository. Use a dedicated IIS Manager user per site so that one compromised pipeline cannot deploy to another site.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Locking Down the Deploy Endpoint<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>msdeploy.axd<\/code> endpoint accepts authentication from anywhere that can reach port 8172, so treat it like an admin interface. Restrict the firewall rule to your build agents or office IP range instead of all addresses:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>netsh advfirewall firewall set rule name=\"Web Deploy 8172\" `\n  new remoteip=203.0.113.10,198.51.100.0\/24\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Also rotate the IIS Manager user password whenever a developer leaves the project. Web Deploy works best when the server is cleanly provisioned with a dedicated app pool per site, known ACLs on the web root, and a firewall that only exposes 8172 to trusted sources. If you are still choosing a hosting provider, the <a href=\"https:\/\/windows-vps.org\/\">Windows VPS plans on our homepage<\/a> list the IIS-related capabilities worth confirming before you sign up.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>FTP-based deployments are fragile. A dropped connection mid-upload, a missing web.config, or mismatched file permissions can take a site offline for minutes. Microsoft Web Deploy (MSDeploy) solves this by using a sync engine that understands IIS structure: it uploads only changed files, applies web.config transformations, and can take the application offline during the swap. This &#8230; <a title=\"How to Publish .NET Apps from Visual Studio to IIS Using Web Deploy\" class=\"read-more\" href=\"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/\" aria-label=\"Read more about How to Publish .NET Apps from Visual Studio to IIS Using Web Deploy\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":4,"footnotes":""},"categories":[5],"tags":[],"class_list":["post-652","post","type-post","status-publish","format-standard","hentry","category-tutorials-guides"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to Publish .NET Apps from Visual Studio to IIS Using Web Deploy - Windows VPS Blog<\/title>\n<meta name=\"description\" content=\"FTP-based deployments are fragile. A dropped connection mid-upload, a missing web.config, or mismatched file permissions can take a site offline for\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Publish .NET Apps from Visual Studio to IIS Using Web Deploy\" \/>\n<meta property=\"og:description\" content=\"How to Publish .NET Apps from Visual Studio to IIS Using Web Deploy\" \/>\n<meta property=\"og:url\" content=\"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/\" \/>\n<meta property=\"og:site_name\" content=\"Windows VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-18T23:12:55+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-08-27T06:15:37+00:00\" \/>\n<meta name=\"author\" content=\"windows-vps\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@myxiechengxuan\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"windows-vps\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/\",\"url\":\"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/\",\"name\":\"How to Publish .NET Apps from Visual Studio to IIS Using Web Deploy - Windows VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/#website\"},\"datePublished\":\"2026-08-18T23:12:55+00:00\",\"dateModified\":\"2026-08-27T06:15:37+00:00\",\"author\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58\"},\"description\":\"FTP-based deployments are fragile. A dropped connection mid-upload, a missing web.config, or mismatched file permissions can take a site offline for\",\"breadcrumb\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/windows-vps.org\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/windows-vps.org\/blog\/#website\",\"url\":\"https:\/\/windows-vps.org\/blog\/\",\"name\":\"Windows VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/windows-vps.org\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58\",\"name\":\"windows-vps\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g\",\"caption\":\"windows-vps\"},\"sameAs\":[\"https:\/\/windows-vps.org\/blog\",\"https:\/\/x.com\/myxiechengxuan\"],\"url\":\"https:\/\/windows-vps.org\/blog\/author\/myxiechengxuan\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to Publish .NET Apps from Visual Studio to IIS Using Web Deploy - Windows VPS Blog","description":"FTP-based deployments are fragile. A dropped connection mid-upload, a missing web.config, or mismatched file permissions can take a site offline for","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/","og_locale":"en_US","og_type":"article","og_title":"How to Publish .NET Apps from Visual Studio to IIS Using Web Deploy","og_description":"How to Publish .NET Apps from Visual Studio to IIS Using Web Deploy","og_url":"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/","og_site_name":"Windows VPS Blog","article_published_time":"2026-08-18T23:12:55+00:00","article_modified_time":"2026-08-27T06:15:37+00:00","author":"windows-vps","twitter_card":"summary_large_image","twitter_creator":"@myxiechengxuan","twitter_misc":{"Written by":"windows-vps","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/","url":"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/","name":"How to Publish .NET Apps from Visual Studio to IIS Using Web Deploy - Windows VPS Blog","isPartOf":{"@id":"https:\/\/windows-vps.org\/blog\/#website"},"datePublished":"2026-08-18T23:12:55+00:00","dateModified":"2026-08-27T06:15:37+00:00","author":{"@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58"},"description":"FTP-based deployments are fragile. A dropped connection mid-upload, a missing web.config, or mismatched file permissions can take a site offline for","breadcrumb":{"@id":"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/windows-vps.org\/blog\/"},{"@type":"ListItem","position":2,"name":"Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors"}]},{"@type":"WebSite","@id":"https:\/\/windows-vps.org\/blog\/#website","url":"https:\/\/windows-vps.org\/blog\/","name":"Windows VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/windows-vps.org\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58","name":"windows-vps","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g","caption":"windows-vps"},"sameAs":["https:\/\/windows-vps.org\/blog","https:\/\/x.com\/myxiechengxuan"],"url":"https:\/\/windows-vps.org\/blog\/author\/myxiechengxuan\/"}]}},"_links":{"self":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts\/652","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/comments?post=652"}],"version-history":[{"count":1,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts\/652\/revisions"}],"predecessor-version":[{"id":653,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts\/652\/revisions\/653"}],"wp:attachment":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/media?parent=652"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/categories?post=652"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/tags?post=652"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}