I recently had the need to deploy an ASP.NET Core web project to an Azure Web App instance from a Linux build agent outside Visual Studio Team Services. As you expect, the world outside the Microsoft development stack is relatively more difficult to integrate, and documentation is still lacking on some of these aspects, unfortunately.

That’s when my Googling endeavor began. How can I deploy an ASP.NET Core build artifact from a Linux build agent outside VSTS — in my case, I was using GitLab — to an Azure Web App instance in an automated way? Using the integrated Deployment Options in the Azure Web App blade was not an option since I was building the app myself.

Fortunately, there’s this deployment management system called Kudu behind every Azure Web App that can be easily be accessed by following this URL: https://{your-webapp-name}.scm.azurewebsites.net. Kudu has a very interesting REST API that we’re going to leverage in order to upload our build artifact in a zipped format so that it automatically unzips and puts the content inside the wwwroot folder without too much of a hassle.

Building the app and zipping the output folder

My build script started with the usual ASP.NET Core build commands:

    1. Restore all the necessary NuGet packages for that project
      dotnet restore
    2. Build the project in Release mode
      dotnet build -c Release
    3. Publish the project to an output folder called out as a deployment artifact
      dotnet publish -c Release -o out
    4. Zip the contents of that folder to a file called out.zip
      cd out; zip -r ../out.zip *; cd ..

Deploying the artifact to the Azure Web App instance using the Kudu Zip Deployment API endpoint – a.k.a The Tricky Part

By the name, it seems really complicated. But it’s really not. All it takes is a one-line command and you’re done. But before that, there’s some date we need to gather.

In order to communicate with your Kudu instance, you have to authenticate. Otherwise, anyone would be able to deploy to your website and that’s not cool. This is the part the documentation starts falling short. In order to see what username and password you should use, you have to download your Publish Profile from your Azure Web App blade:

Directions to where the Get publish profile button is

With your publish profile in hands, look for the first <publishProfile> tag — the one that is named {your-website-name} – Web Deploy — and find the attributes called userName and userPWD. Get their values and keep them somewhere, you’re going to need them later.

With those in hand, open your deployment script and add the following line:

curl -X POST -u '{userName}':{userPWD} --data-binary @out.zip https://{your-webapp-name}.scm.azurewebsites.net/api/zipdeploy

Let’s understand this line a little further. We’re using curl to make an HTTP POST request to our Kudu instance REST API endpoint for the zip deployment system with a payload containing our build artifact from before.

  • -u ‘{userName}’:{userPWD} – the -u means user, we’re authenticating the request with the username and password from our publish profile. Keep in mind your username might have a dollar sign ($) in it, therefore we have to put it inside a single quote so it’s not understood as an environment variable.
  • –data-binary @out.zip – that’s our payload, the files zipped from the previous step during the build process. If you named your file differently, make sure you insert the right name here. Kudu then automatically unzips our files and places them inside the wwwroot folder.
  • https://{your-webapp-name}.scm.azurewebsites.net/… – that’s your Kudu instance address. Replace the {your-webapp-name} part with your actual web app name.

Verifying your deployment

To check whether this really worked, navigate to your Kudu homepage — again {your-webapp-name}.scm.azurewebsites.net — click on Debug Console on your top navigation bar, then CMD. Navigate to site/wwwroot and check whether your build artifact files are there directly inside this folder.

They are? Cool. Head to {your-webapp-name}.azurewebsites.net and check whether your website successfully loads. Mine did:

The asp.net core website successfully loaded

P.S.: I built using GitLab, this is how my .gitlab-ci.yml file looked like