Continuous Deployment, NodeJS and Microsoft Azure

I’m progressing nicely on my side project. I’ve got a base server running in NodeJS and a nice web client that can be built using Gulp. I’m getting to the point where I want to run it in the cloud. That means creating an application within Microsoft Azure and setting up continuous deployment from GitHub. There are some gotchas to consider, so this post is all about avoiding the pitfalls and getting the application deployed. For this post, I’m going to use my honeydo application. Currently, it’s a simple NodeJS express server that serves up content from a wwwroot directory. I store my client side in webclient. It’s written in ES6 and uses a React/Flux architecture.

So, what’s the problem? The default Azure deployment assumes your files are ready to go and need no processing at all. Mine do – I need to turn the less files into CSS and I need to build the web client from the ES6 files, minify everything and combine the client using browserify. There is a build process. When you have a build process, you don’t check in the built files, so that means they are not available to Azure directly.

There is an easy way around this. Azure has a deployment script – you just have to set it up to run the build script. Here is how to do it.

Step 1: Create a Deployment Script

There is a simple way to generate some needed files and that’s via the Azure CLI utility. It’s distributed in npm, so just do the following (if you don’t already have it):

npm install -g azure-cli

You should be able to run the azure command directory now – it displays some help if you run it without arguments. You can get this separately as well, but I like npm. This is a one-time task, so once you have it, you are set. You can use this new command to create the initial deployment scripts:

azure site deploymentscript --node

This will create two files – .deployment and deploy.cmd. The .deployment file is simple enough:

command = deploy.cmd

Basically, it tells the Azure deployment system to run the deploy.cmd file that is also created. I’m not going to show off the deploy.cmd – it’s fairly long. It checks for the node version that you require and then copies the files from the repository to the IIS service area.

Step 2: Adjust deploy.cmd for building

By default, the deploy.cmd script doesn’t build before deploying. There are two changes. Firstly, you must remove the --production flag from the npm install so that all the packages are downloaded including the ones for building the system. Secondly, you have to add a step to build the client. Here are my (highlighted) changes:

echo Handling node.js deployment.

:: 1. KuduSync
  call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_SOURCE%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
  IF !ERRORLEVEL! NEQ 0 goto error

:: 2. Select node version
call :SelectNodeVersion

:: 3. Install npm packages
  call :ExecuteCmd !NPM_CMD! install
  IF !ERRORLEVEL! NEQ 0 goto error

:: 4. Build the webclient
  echo "Building web site using Gulp"
  call :ExecuteCmd ".\node_modules\.bin\gulp.cmd"
  if !ERRORLEVEL! NEQ 0 goto error

In this snippet of the file, like 103 is where I removed the --production flag. I also added building the webclient into wwwroot. It’s conditional on the existence of a Gulpfile.js. Note that I am using the version inside of the node_modules\.bin directory. I would recommend removing your node_modules directory (with rimraf), then running npm install and .\node_modules\.bin\gulp.cmd – sometimes you forget that --save (or --save-dev) flag to npm install. At that point it works on your machine but deployment fails because the library isn’t being downloaded. Wiping node_modules and typing the EXACT commands that is in the deployment script is a good way to highlight that before checking in.

Step 3: Set up an Azure Web App

First off, you have an Azure account right? If not, sign up for a trial. My MSDN license comes with free credits and the web site I am going to deploy is on the free tier, so this experiment will not cost me anything. I’m going to be using the preview portal, so log in and follow along.

Once you have logged into the preview portal, Click on the big + NEW in the top left corner, select Web + Mobile and then Web App.


The appname must be unique as it is exposed in the domain – mine is ahall-honeydo-app. You will want to type in the name in two places – the obvious one (under Web App) and the not-so-obvious one – in the Resource Group box that is currently occupied by the word Default. Resource Groups allow you to group all the resources for a specific service together. If you delete the resource group, all the resources for the service go. If you miss this step, you’ll have to delete each individual resource individually later. This can be a major pain if you add and delete services regularly. Always create a Resource Group when you create a service.


In addition to the name of the app, you will want to pick a pricing tier and region. You do this by creating a pricing plan. Click on the App Service Plan and then Create New.


Select a name (I make mine all linked together and obvious), select a region (potentially close to you as this is a test environment), and a pricing plan. You will have to click on View All to get the free and shared tiers. If you change the pricing plan, remember to click on Select. Once that is done, click on OK to save the pricing plan.

You are now ready to create the web application – click on the Create button in the Web app blade. You will be taken back to the portal home page and a tile will be added for your app. Initially, it will be deploying (and that can take a couple of minutes to deploy). Once the deployment is finished, a blade will open for your web app:


Step 4: Set up Continuous Deployment

Of course, right now you have an empty web app. You need to deploy some files there. You could, of course, just use ftp to upload the files. You could also publish via Visual Studio or something scripted. However, I promised a continuous deployment. That means that when I push my changes to GitHub, it gets reflected on the Azure site. To do that, I’m going to create a new branch called “azure” using git:

git branch azure
git checkout azure
git push --set-upstream origin azure

I never publish “master” although there is nothing to stop you doing so. That’s bad form. Create a branch and then merge changes you want to deploy from the appropriate branch to the azure branch. The git branch command creates the branch. The git checkout command switches to the new branch, and the git push command sets up uploading of the branch to GitHub. Once this is done, you can just use git push – you don’t need the set-upstream bit. Before you continue, make sure the azure branch is available on GitHub.

If you’ve closed the Web app blade that was opened when you created the web app, you can re-open it by selecting Browse All and then clicking on the web app name. Once there, scroll down to the Deployment section:


Click on the Set up continuous deployment button. Note how large and obvious it is – yes. This is the preferred way of doing things. Click on Select Source and select GitHub.


You will have to authorize the GitHub request on the first time through. Next, tell Azure which project it is going to host:


Next, click on the Select Branch and select your azure branch. Then click on OK and wait for the deployment to happen. After a few moments, you will see your last checkin getting built. Remember that the first time through, Azure is cloning the repository, pulling down all the npm packages and then building the code. It may take a few minutes!

If the deployment fails, you will have access to the Audit log – just click on the failed deployment and select the entry that has a View log link. Generally, the gulp output is there. If you don’t have a gulp output in there, then it’s likely that gulp itself has errored. Run the gulp file outside of Azure deployment with a clean clone to see what the error is. When gulp can run, it will produce the normal output in the log file.

Once it has finished building for the first time, you will be able to hit the endpoint. Mine is – it may not be running or it may be broken or just plain slow because I’m on the free tier, so don’t hit mine. Deploy your own!

Final Cautions

Azure looks for a server boot file called app.js or server.js – I placed my server boot file in bin/server.js and it works just fine. I wish that Azure would support npm start or the main file in package.json but it doesn’t seem to. If your server isn’t running, you should check that.

Finally, note that the default version of Node on Azure is currently v0.10. You can specify a version of Node by using the engines directive in your package.json file. I use v0.12 right now, so I can add the following:

  "engines": {
    "node": ">=0.12.4"

The deployment will fail if the restriction cannot be met, but you will be given a list of available Node versions in the activity log and can adjust accordingly.