Deploying multiple apps to an Azure Website with Kudu

Walkthrough

Source code for a trivial sample project with two applications that are deployed as separate virtual applications can be found here. The applications themselves are not particularly interesting, but I published it to highlight how few changes are required to get it working.

Note: Sample source code is based on amitapl/CustomScriptSample which puts both projects in the same repository. However, you can also deploy projects from separate repositories using these instructions. Just be aware of the considerations I’ve listed at the bottom of this article.

Create a virtual application in the Azure portal

For each project you’d like to deploy, create a virtual application. Specify a path to a folder that is next to the existing wwwroot folder - i.e. site\<name> - and mark it as an application.

Configure your app service for deployment

On the blade for your App Service, go to “Deployment options”.

If your apps are hosted in separate repositories, select “Internal git repository”. It creates a remote repository at <sitename>.scm.azurewebsites.net, which is preconfigured to trigger a deployment anytime you push to its master branch and enables the list of deployments in the Azure portal. Just ignore this repository; it will remain empty.

If your apps are hosted in a single repository, you can also select “External repository” and configure your repository. This enables a “sync” button in the Azure portal, in addtion to the list of deployments, which can be used to manually trigger a pull and deploy from the external repository. I guess this is useful in the event that your webhook isn’t working.

Generate deployment script(s)

If you don’t already have one. Using one of the following commands, depending on your project type:

azure site deploymentscript --aspWAP <ProjectFile.csproj> -s <SolutionFile.sln>
azure site deploymentscript --node

Modify deploy.cmd

For each application being deployed as virtual applications, change the DEPLOYMENT_TARGET to match the path of the virtual application you created.

Note: Kudu sets the deployment target environment variable and deploy.cmd only sets the variable if it not already defined, so you have to add an else branch to modify the value set by Kudu.:

...
IF NOT DEFINED DEPLOYMENT_TARGET (
  SET DEPLOYMENT_TARGET=%ARTIFACTS%\<VIRTUAL_APP_PATH>
) ELSE (
  SET DEPLOYMENT_TARGET=%DEPLOYMENT_TARGET:wwwroot=<VIRTUAL_APP_PATH>%
)
...

Notify Kudu of changes

Set up a webhook that is triggered on push and calls the following url:

https://<username>:<password>@<sitename>.scm.azurewebsites.net/deploy

Gitlab webhooks work out of the box. On Github, make sure you choose JSON for the payload format.

To get the username and password, go to the Overview tab of your app service in the Azure portal. Open the overflow menu by clicking “… More” and select “Get publish profile”.

Open the publishSettings file in a text editor and look for the userName attribute with a value that starts with $ - usually $<sitename> - and a userPWD attribute with a very long value.

Other considerations

Base URL

You may need to modify your application to make all routes and urls relative to a base url. You can either hardcode this base path or load it from an evironment variable, which can be set as an App Setting in the Azure portal. Using an environment variable has the benefit of allow you to use the root directory in development and a subdirectory in production.

Notes on deploying from separate repositories

Rollback

The Azure portal displays a list of deployments, their statuses and enable one-click rollbacks. If you deploy from separate repositories, only your latest deployment is marked as active - even though you will technically always have two active deployments - and the rollback functionality is completely untested.

One webhook per project

The only other difference is that you obviously need to notify Kudu of changes for each project that you want it to deploy.