{"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-18T23:12:55","modified_gmt":"2026-08-18T23:12:55","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":"Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors"},"content":{"rendered":"<p class=\"wp-block-paragraph\">FTP was how .NET apps got deployed for years, and it is still how sites get broken: a half-uploaded file, a lost <code>web.config<\/code>, a permissions fight. Microsoft Web Deploy (MSDeploy) replaces that with a sync engine that understands IIS &#8211; it uploads only what changed, applies web.config transforms, and can take the app offline during the swap. This is the setup for publishing from Visual Studio to a Windows VPS running IIS.<\/p>\n<h2 class=\"wp-block-heading\">Install Web Deploy on the server<\/h2>\n<p class=\"wp-block-paragraph\">Download the Web Deploy installer (the current 4.x MSI, available from the official Microsoft download page) and choose <strong>Complete<\/strong> install. The Typical option installs only the client tool; Complete adds the <em>handler<\/em>, which is what lets remote machines publish:<\/p>\n<pre class=\"wp-block-code\"><code># Confirm the handler is registered after install\n&amp; &quot;$env:ProgramFiles\\IIS\\Microsoft Web Deploy V4\\msdeploy.exe&quot; -version<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Enable remote management and create a deploy user<\/h2>\n<p class=\"wp-block-paragraph\">In IIS Manager, open the server node and go to <strong>Management Service<\/strong>. Enable remote management on the default port <strong>8172<\/strong> with HTTPS, then create an IIS Manager user (under <strong>IIS Manager Users<\/strong>) &#8211; this avoids handing out a Windows account. Finally, on the target site, open <strong>IIS Manager Permissions<\/strong>, add that user, and grant <strong>Content Management<\/strong> delegation so it can read and write the site folder but nothing else.<\/p>\n<pre class=\"wp-block-code\"><code>netsh advfirewall firewall add rule name=&quot;Web Deploy 8172&quot; dir=in action=allow `\n  protocol=TCP localport=8172<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The management service endpoint is <code>https:\/\/yourserver:8172\/msdeploy.axd<\/code>. Test it from your workstation before involving Visual Studio:<\/p>\n<pre class=\"wp-block-code\"><code>msdeploy.exe -verb:dump `\n  -dest:computerName=&quot;https:\/\/yourserver:8172\/msdeploy.axd&quot;,userName=&quot;webdeploy&quot;,password=&quot;***&quot;,authType=&quot;Basic&quot;,`\n  -allowUntrusted<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Publish profile in Visual Studio<\/h2>\n<ul class=\"wp-block-list\"><li>Right-click the project, <strong>Publish<\/strong> \u2192 <strong>New profile<\/strong> \u2192 <strong>Web Deploy<\/strong>.<\/li><li>Server: <code>https:\/\/yourserver:8172\/msdeploy.axd<\/code>; Site name: the IIS site name (e.g. <code>contoso<\/code>); user\/password: the IIS Manager user.<\/li><li>Enable <strong>Remove additional files at destination<\/strong> for clean builds (it deletes orphaned files &#8211; disable it if you upload user content to the site folder).<\/li><li>Add a <code>Web.Release.config<\/code> with <code>xdt:Transform<\/code> entries to swap connection strings and app settings per environment.<\/li><\/ul>\n<p class=\"wp-block-paragraph\">Before the first real deploy, use Visual Studio&#8217;s <strong>Preview<\/strong> step in the publish dialog: it lists every file that will be added, updated or deleted on the server without touching anything. A five-second glance at the preview catches the classic mistakes &#8211; a missing <code>appsettings.json<\/code>, a stray <code>bin<\/code> folder, or a transform that dropped a connection string.<\/p>\n<pre class=\"wp-block-code\"><code>&lt;!-- Web.Release.config --&gt;\n&lt;configuration xmlns:xdt=&quot;http:\/\/schemas.microsoft.com\/XML-Document-Transform&quot;&gt;\n  &lt;connectionStrings&gt;\n    &lt;add name=&quot;Default&quot; connectionString=&quot;Server=.;Database=app;User ID=app;Password=***&quot;\n         xdt:Transform=&quot;SetAttributes&quot; xdt:Locator=&quot;Match(name)&quot; \/&gt;\n  &lt;\/connectionStrings&gt;\n&lt;\/configuration&gt;<\/code><\/pre>\n<h2 class=\"wp-block-heading\">The 5 errors everyone hits (and the fixes)<\/h2>\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 Content Management 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 the service 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>Give the IIS Manager user or app pool identity Modify on the site folder (icacls)<\/td><\/tr><tr><td>ERROR_FILE_IN_USE \/ locked files<\/td><td>w3wp.exe holds the old DLLs<\/td><td>Drop an app_offline.htm into the site root before sync (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 Complete; restart Management Service<\/td><\/tr><\/tbody><\/table><\/figure>\n<p class=\"wp-block-paragraph\">The locked-file problem deserves extra attention: Web Deploy can take the app offline automatically, but the reliable pattern for a busy site is to place <code>app_offline.htm<\/code> in the root, publish, then delete it. IIS sees the file, unloads the app pool, and no process holds the files.<\/p>\n<h2 class=\"wp-block-heading\">Using the same pipeline for CI\/CD<\/h2>\n<p class=\"wp-block-paragraph\">The Visual Studio profile is just a wrapper around <code>msdeploy.exe<\/code>. Your build agent can do the identical sync from the command line:<\/p>\n<pre class=\"wp-block-code\"><code>msdeploy.exe -verb:sync -source:package=&quot;artifacts\\site.zip&quot; `\n  -dest:auto,computerName=&quot;https:\/\/yourserver:8172\/msdeploy.axd&quot;,userName=&quot;webdeploy&quot;,password=&quot;***&quot;,authType=&quot;Basic&quot; `\n  -setParam:name=&quot;IIS Web Application Name&quot;,value=&quot;contoso&quot; `\n  -allowUntrusted<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Store the password in the build agent secret store, never in the repo. A dedicated IIS Manager user per site keeps one pipeline from deploying to another site, and the per-site delegation model means a compromised build agent can touch only its own folder.<\/p>\n<h2 class=\"wp-block-heading\">Locking down the deploy endpoint<\/h2>\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, prefer IIS Manager users over local Administrator credentials, and rotate the password whenever a developer leaves the project:<\/p>\n<pre class=\"wp-block-code\"><code>netsh advfirewall firewall set rule name=&quot;Web Deploy 8172&quot; new remoteip=203.0.113.10,198.51.100.0\/24<\/code><\/pre>\n<p class=\"wp-block-paragraph\">For unattended syncs, add <code>-enableRule:AppOffline<\/code> to the msdeploy command: it drops <code>app_offline.htm<\/code> automatically before syncing and removes it afterwards, which eliminates the locked-file race without manual steps.<\/p>\n<h2 class=\"wp-block-heading\">Before you wire up the pipeline<\/h2>\n<p class=\"wp-block-paragraph\">Web Deploy works best when the server is cleanly provisioned: dedicated app pool per site, known ACLs on the web root, and a firewall that only exposes 8172 to your build agents or office IPs. If you are still choosing where to host, the <a href=\"https:\/\/windows-vps.org\/#providers\">Windows VPS comparison table on our site<\/a> compares providers by admin access and networking, and the <a href=\"https:\/\/windows-vps.org\/#features\">feature checklist on our site<\/a> lists the IIS-related capabilities worth confirming before you sign up.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>FTP was how .NET apps got deployed for years, and it is still how sites get broken: a half-uploaded file, a lost web.config, a permissions fight. Microsoft Web Deploy (MSDeploy) replaces that with a sync engine that understands IIS &#8211; it uploads only what changed, applies web.config transforms, and can take the app offline during &#8230; <a title=\"Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors\" class=\"read-more\" href=\"https:\/\/windows-vps.org\/blog\/iis-web-deploy-publish-aspnet-visual-studio\/\" aria-label=\"Read more about Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors\">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":0,"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>Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors - Windows VPS Blog<\/title>\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=\"Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors\" \/>\n<meta property=\"og:description\" content=\"Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors\" \/>\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 name=\"author\" content=\"windows-vps\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\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\":\"Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors - Windows VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/#website\"},\"datePublished\":\"2026-08-18T23:12:55+00:00\",\"author\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58\"},\"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\"],\"url\":\"https:\/\/windows-vps.org\/blog\/author\/myxiechengxuan\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors - Windows VPS Blog","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":"Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors","og_description":"Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors","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","author":"windows-vps","twitter_card":"summary_large_image","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":"Publish from Visual Studio to IIS with Web Deploy: Setup, Permissions, and the 5 Most Common Errors - Windows VPS Blog","isPartOf":{"@id":"https:\/\/windows-vps.org\/blog\/#website"},"datePublished":"2026-08-18T23:12:55+00:00","author":{"@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58"},"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"],"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}]}}