Publish Application with MSDeploy Workflow

February 6, 2026 ยท View on GitHub

This reusable GitHub Actions workflow automates the process of building and deploying .NET and/or SPA (Single Page Application) projects to IIS servers using Microsoft Web Deploy (MSDeploy). It provides flexibility to build and deploy either or both project types, combining artifacts when both are present.

Functionality Summary

The Publish Application with MSDeploy workflow includes the following features:

  • .NET Backend Build:

    • Restores NuGet packages and builds the .NET application.
    • Publishes the .NET application to a build output directory.
    • Supports adding private NuGet sources based on provided accounts and secrets.
    • Adds a GitHub release asset, if applicable, with the .NET application
  • SPA Frontend Build:

    • Installs NPM dependencies and builds the SPA application using a specified NPM script.
    • Uploads the built SPA artifact and optionally a persisted documents file.
    • Adds a GitHub release asset, if applicable, with the SPA application
  • Deployment to IIS with MSDeploy:

    • Deploys the .NET application to IIS via MSDeploy.
    • Deploys SPA-only applications to the root of the IIS site.
    • When both .NET and SPA are present, combines them before deployment (SPA goes to wwwroot).
    • Supports Basic authentication and configurable SSL certificate validation.
  • Conditional Execution:

    • Workflow steps are conditionally executed based on the inputs provided.
    • Skips .NET steps if dotnet_folder is not specified.
    • Skips SPA steps if spa_folder is not specified.
    • Build jobs run regardless of whether MSDeploy is configured.
    • Deployment jobs only run if MSDeploy configuration is provided.
    • Release assets are created whenever builds run, regardless of deployment configuration.

Configuration Options

Common Inputs

Input NameDescriptionRequiredDefault Value
environment_nameSpecifies the GitHub environment to use while building and for MSDeploy authenticationYesNone

.NET Build Inputs

Input NameDescriptionRequiredDefault ValueComments
dotnet_folderPath to the .NET project folderNoNoneOmitting skips .NET-related steps
global_json_folderPath to the folder containing global.jsonNo.Ignores dotnet_folder when resolving path
nuget_accountsComma-separated list of GitHub accounts for NuGet sourcesNoRepository ownerSkipped if tokens are not provided
npm_accountsComma-separated list of GitHub accounts for NPM sourcesNoRepository ownerSkipped if tokens are not provided
dotnet_configuration.NET build configuration (e.g., Release, Debug)NoRelease

SPA Build Inputs

Input NameDescriptionRequiredDefault ValueComments
spa_folderPath to the SPA project folderNoNoneOmitting skips SPA-related steps
spa_version_envEnvironment variable to set with the version numberNoVITE_VERSIONe.g. REACT_APP_VERSION for React
npm_build_scriptNPM script used to build the SPA applicationNobuild
npm_dist_folderPath to the SPA distribution folder (relative to spa_folder)Nodist
persisted_documents_filePath to the persisted documents file to copy to .NET build folderNoNone
npm_analyze_scriptNPM script to run after build for analysisNoNone
analysis_artifactsFull path to files to upload as analysis artifacts (glob pattern)NoNone

MSDeploy Configuration Inputs

Input NameDescriptionRequiredDefault Value
msdeploy_server_urlMSDeploy server URL for deploymentNoNone
msdeploy_site_nameIIS site name for deploymentNoNone
msdeploy_usernameUsername for MSDeploy authenticationNoNone
msdeploy_allow_untrustedAllow untrusted SSL certificatesNofalse
msdeploy_do_not_deletePrevent deletion of files not in sourceNofalse

Environment Variables

If an environment is configured, variables configured for the specified environment are used as shell environment variables when building the code.

Required Variables, Inputs, or Secrets

The workflow requires the following MSDeploy configuration values to be provided either as:

  • Workflow inputs (as shown in the table above)
  • Repository/Environment variables with these names
  • Secrets (for sensitive values like passwords)
Variable NameDescriptionRequiredDefault Value
MSDEPLOY_SERVER_URLMSDeploy server URL for deploymentNo (will skip deployment if not specified)None
MSDEPLOY_SITE_NAMEIIS site name for deploymentNo (will skip deployment if not specified)None
MSDEPLOY_USERNAMEUsername for MSDeploy authenticationNo (will skip deployment if not specified)None
MSDEPLOY_PASSWORDPassword for MSDeploy authenticationNo (will skip deployment if not specified)None

The workflow will first check for values provided as inputs or secrets, and if not found, will fall back to repository or environment variables. If neither is available, the workflow will skip deployment steps but will still build the application and create release assets.

Secrets

Secret NameDescriptionRequiredDefault Value
NUGET_ORG_USERUsername for private NuGet source (if applicable)NoNone
NUGET_ORG_TOKENToken for private NuGet source (if applicable)NoNone
NPM_TOKENGitHub Personal Access Token for private npm packagesNoNone
msdeploy_passwordPassword for MSDeploy authenticationNoNone

Example Usage Scripts

1. Deploy .NET Application to IIS for development

name: Deploy .NET Application

on:
  push:
    branches:
      - master

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  publish-application:
    uses: Shane32/SharedWorkflows/.github/workflows/publish-app-msbuild.yml@v2
    permissions:
      contents: write
    with:
      dotnet_folder: '.'
      environment_name: Development
    secrets:
      NUGET_ORG_USER: ${{ secrets.NUGET_ORG_USER }}
      NUGET_ORG_TOKEN: ${{ secrets.NUGET_ORG_TOKEN }}
      msdeploy_password: ${{ secrets.MSDEPLOY_PASSWORD }}

The above example assumes that the necessary MSDeploy configuration values are stored as GitHub environment variables for the Development environment, with the password stored as a secret.

2. Deploy SPA Only to IIS for development

name: Deploy SPA Application

on:
  push:
    branches:
      - master

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  publish-application:
    uses: Shane32/SharedWorkflows/.github/workflows/publish-app-msbuild.yml@v2
    permissions:
      contents: write
    with:
      spa_folder: ReactApp
      environment_name: Development
      msdeploy_server_url: https://dev-server.example.com:8172/msdeploy.axd
      msdeploy_site_name: DevSite
      msdeploy_username: deploy-user
    secrets:
      msdeploy_password: ${{ secrets.MSDEPLOY_DEV_PASSWORD }}

The above example shows how to provide MSDeploy configuration values as workflow inputs, with the password passed as a secret.

3. Deploy Full Application (Backend and SPA) to IIS for production

name: Deploy Full Application

on:
  release:
    types:
      - published

jobs:
  publish-application:
    uses: Shane32/SharedWorkflows/.github/workflows/publish-app-msbuild.yml@v2
    permissions:
      contents: write
    with:
      dotnet_folder: '.'
      spa_folder: ReactApp
      environment_name: Production
    secrets:
      NUGET_ORG_USER: ${{ secrets.NUGET_ORG_USER }}
      NUGET_ORG_TOKEN: ${{ secrets.NUGET_ORG_TOKEN }}
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

The above example assumes that the necessary MSDeploy configuration values are stored as GitHub environment variables, and only passes the required NuGet secrets. When both .NET and SPA are specified, the SPA will be automatically deployed to the wwwroot folder within the IIS site.

Notes

  • Unlike the Azure version, this workflow does not have a spa_deployment_method input
  • When deploying SPA-only (no .NET), the SPA is deployed to the root of the IIS site
  • When both .NET and SPA are present, they are automatically combined before deployment (SPA goes to wwwroot)
  • The workflow runs on Windows runners for deployment due to MSDeploy requirements
  • NUGET_ORG_USER, NUGET_ORG_TOKEN, and NPM_TOKEN should already be configured as organization secrets but need to be passed in.
  • global.json is required
  • Cannot override .NET SDK with another version or install multiple SDKs
  • permissions: contents: write is necessary to upload the compiled application as a release asset
  • The msdeploy_allow_untrusted option should only be set to true for development/staging environments with self-signed certificates

MSDeploy Server URL Format

The MSDeploy server URL typically follows this format:

https://server-name:8172/msdeploy.axd?site=site-name

Where:

  • server-name is your IIS server hostname or IP address
  • 8172 is the default MSDeploy port (may vary based on your configuration)
  • /msdeploy.axd is the MSDeploy handler endpoint
  • site-name is the site name (e.g. Default Web Site) and does not include the application name, if any

IIS Site Name

The IIS site name should match the exact name of the website or application in IIS where you want to deploy. For deploying to a specific application within a site, use the format:

SiteName/ApplicationName