Deploying multiple apps to an Azure Website with Kudu


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>, 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.:

) ELSE (

Notify Kudu of changes

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


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


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.

The Case of the Missing Bluetooth Address

Android 6.0 (Marshmallow) was released about 4 months ago and it brought some welcome changes - such as runtime permissions - as well as some not-so-welcome changes - such as the unceremonial removal of the BluetoothAdapter.getAddress() api.

The History

Prior to Android M, getting the Bluetooth address was a relatively simple affair:

BluetoothAdapter adapter = getAdapter();

if (adapter != null) {
    String address = adapter.getAddress();
} else {
    // Device does not support Bluetooth

Unfortunately, advertisers have been abusing this api to uniquely identify users in a way that would allow them to continue to track a user even if they uninstalled and reinstalled an app. Since the Bluetooth address comes from the device hardware, they are even able to stay on the trail of a user that factory reset their phone! Which is why BluetoothAdapter.getAddress() and WifiInfo.getMacAddress(), the two apis that gave developers access to hardware identifiers, were removed in Marshmallow.

The Problem

The abuse cases were bad and I’m glad Google is putting a stop to it, but there were legitimate uses for these apis and abruptly removing them has caused problems. Instead of throwing an exception and making the application crash, Google chose to return a dummy address - 02:00:00:00:00:00 - which is fine, if you are using the address for tracking purposes.

Apps that are using it for tracking will suddenly see a ton of activity from a “single” user, realize what has happened and filter out that data. Eventually they can update their app to track users a different way.

Legitimate uses of the Bluetooth address rely on BluetoothAdapter.getAddress() returning the actual, working Bluetooth address for the device. For instance, SocketScan uses the Bluetooth address during the scanner pairing process.

The way it works is that we display a barcode on the screen that contains the Bluetooth address of your Android device, when the scanner reads that barcode, it reconfigures itself and starts trying to connect to the Bluetooth device at the address it just received. It is a simple trick to make the scanner initiate the connection even though there is no screen on the scanner for you to select the device to which it should connect.

The problem with Google’s quick fix is that legitimate use cases of the Bluetooth address don’t just fail, they fail silently.

The Fix

Unfortunately, it appears the only way to get the Bluetooth address of a marshmallow device is to ask the user. However, there are a few things that can smooth the transition.

Cache the Bluetooth address while you still can. Marshmallow just crossed the 1% threshold of active Android devices, so there is a good chance your app still has access to the Bluetooth address. If you cache the Bluetooth address now, you can still access it after the device is upgrades to marshmallow. We are using a wrapper class that tries to retrieve the Bluetooth address from shared preferences before trying the adapter and if the adapter returns a valid address (i.e. not 02:00:00:00:00:00) it saves the address to shared preferences before returning it to the caller.

Make it easy for the user. Bluetooth addresses are not user-friendly. They are difficult to type and even more difficult to remember. Even though the user has to provide your app with their device’s Bluetooth address, it doesn’t mean they have to type it. We link the user directly to Settings > About Phone > Status where they can long-press the Bluetooth address† to copy it to their clipboard and paste it into the EditText when they return to our activity.

† The Bluetooth address is only available, if Bluetooth is ON.

Show me the code

Our BluetoothUtils is available as a gist.

A Little Git Trick

Ever find yourself wanting to check the status of every git repo inside a particular folder? Of course you do.

# OSX or FreeBSD
find . -type d -name .git |
  xargs -n1 dirname |
  xargs -I {} git -C {} status
# GNU variants
find . -type d -name .git -printf '%h\n' |
  xargs -I {} git -C {} status

status can obviously be replaced with the git command of your choice. For instance, log -1 --pretty=oneline

Requires git 1.8.5

Angular Boilerplate Plus

Most of the Angular tutorials online use trivial examples to illustrate a very specific point and don’t provide any guidance on how to structure an Angular project. Unless your app is limited to one controller and one directive, it’s something you’ll need to think about. Fortunately, Josh D. Miller published Angular Boilerplate so we don’t need to think too hard.

What Angular Boilerplate, or ngbp, does is it tries to set forth some best practices for structuring a non-trivial angular apps. (Ironically, ngbp is not a sample app, so it provides a trivial app to demonstrate how to structure a non-trivial app.)

Building (grunt)

Out of the box ngbp gives you some handy grunt tasks.

grunt build - Builds/compiles less and coffeescript into css and javascript, respectively. Converts your templates into js to reduce the number of queries the application makes to the server. It copies everything into the build folder and runs your tests.

grunt watch - Builds then rebuilds if it detects any changes to the source files (i.e. files in src/ and vendor/). The caveat here is that it will only detect changes to existing files. If you add a new module or template, you’ll need to stop and restart grunt watch.

grunt compile - Concatenates and minifies all the css and javascript files in your build folder into one neatly packaged css and javascript file in your bin folder.

Routing (ui-router)

ui-router let’s you organize your app and urls around states, instead of trying to organize your app around urls. States can be nested and child states inherit their parent’s scope. Functionally this means that you can define a parent state which lists all of the objects in a collection and clicking an object transitions the user to a child state (for example, a detail view of the selected object). The child state has access to the collection defined in the parent state, so you don’t need to re-fetch the object from the server to display it. Changes made to the object in the child state are reflected in the parent state when the user transitions back to it.

Compiling (ngmin)

When I started with ngbp, I was surprised that the sample modules weren’t annotated. Everybody knows you need annotations if you want to minify your angular app! Right? In my naiveté I started adding all the missing annotations.

// Breaks when minified
angular.module('myMod', [])
.controller('MyController', function($scope) {
    $scope.key = value;

// Works when minified
angular.module('myMod', [])
.controller('MyController', [ '$scope',
    function MyController (    $scope) {
    $scope.key = value;

// I even line up the names to make sure I've got them all

It turns out ngbp wasn’t raised by no fool and you don’t need to write annotations, because the annotations are added automatically by ngmin during the compile step. Very clever! Except ngmin doesn’t annotate all dependency injections, most notably, those injected into resolves in a ui-router state.

angular.module('myApp.area', [ 'ui-router'] )

// Annotated by ngmin
.config(function($stateProvider) {
    .state('myState', {
        url: '/items/:id',
        controller: 'StateCtrl',
        resolve: {
            // NOT annotated by ngmin
            item: function($http, $stateParams) {
                return $http.get('/api/' + $stateParams['id'])
                    function success(response) {
                        return response;

Fortunately, there is a simple fix: ng-annotate. ng-annotate has nominated itself to be the successor to ngmin and has the backing of the author of ngmin himself, so it’s probably just a matter of time before ngbp ships with ng-annotate, but until it does, you’ll need to switch manually.

`# Remove ngmin and it's dependencies`
npm uninstall grunt-ngmin --save-dev
`# Install grunt-ng-annotate and it's dependencies`
npm install grunt-ng-annotate --save-dev
`# Update the grunt tasks to use grunt-ng-annotate`
sed -i "" -e 's/grunt-ngmin/grunt-ng-annotate/g' Gruntfile.js
sed -i "" -e 's/ngmin/ngAnnotate/g' Gruntfile.js
`# Not strictly necessary, just updates a comment`
sed -i "" -e 's/ng-min/ngAnnotate/g' Gruntfile.js

Settings (environment variables)

It is not uncommon to use different variables in different environments. For example, a local api endpoint for development and the real api endpoint for production. While ngbp doesn’t support it out of the box, it’s easy enough to add yourself.

  1. Create your environment specific configuration files
// file: src/conf/dev.js
angular.module('myApp.settings', [])
.constant('config', {
    'html5Mode': false
// file: src/conf/prod.js
angular.module('myApp.config', [])
.constant('settings', {
    'html5Mode': true
  1. Use the values in your app
// file: src/app.js
angular.module('myApp', [
.config(function($locationProvider, settings) {


  1. Set a default environment
// file: build.config.js
module.exports = {
    env: 'dev',
  1. Update your build task
// file: Gruntfile.js


// Rename the build task to ngbpbuild
grunt.registerTask( 'ngbpbuild', [
    'clean', 'html2js', 'jshint', 'coffeelint', 'coffee', 'less:build', 'concat:build_css', 'copy:build_app_assets', 'copy:build_vendor_assets', 'copy:build_appjs', 'copy:build_vendorjs', 'index:build', 'karmaconfig', 'karma:continuous'

// Create a new env aware build task
// Sets the env and calls the old (renamed) build task
grunt.registerTask( 'build', function(env) {
    env = env || grunt.config.get("env") || "dev";
    grunt.config.set("env", env);"ngbpbuild");



I’d recommend ngbp as a starting point for any angular app, even trivial ones, because weren’t all non-trivial apps trivial at some point?

The magic of ngbp is in the Gruntfile. By automatically discovering and adding project files to index.html during grunt build, ngbp makes it easy to create and maintain a sensible project structure, even if it’s not the structure they prescribe. And ng-annotate and grunt watch, a grunt task that detect changes, rebuilds the project and reloads your browser, eliminate a lot of the repetition of angular development. Good project structure and automating repetitive tasks are a recipe for greater productivity and ultimately that’s the goal-to be productive.