I’ve been using Node.js quite a lot lately as I find it a nice quick way to get web projects started easily, and one of the things I’ve been doing is deploying and running my Node.js apps in Azure. Azure provides a number of ways of to run Node.js code within the platform, but I’ll be focusing on the PaaS Azure App Services or Web Apps (more info), rather than VMs or anything strange.
Why write a blog about this? Isn’t using Node.js with Azure Web Apps all easy and already documented? Well… kinda, there is documentation but there’s also a lot of gotchas, semi-hidden features and things I stumbled across which made me feel like gathering all these nuggets of info into one place
In this post I’ll focus on “normal” App Services (which are Windows based), I’ll cover the newer Linux App Services in a second post. They are a much better option for running Node.js in my opinion
Being a PaaS (Platform as a Service) offering, Azure App Services make life easy for developers, they provide a simple way to deploy and run your code, all the messing with VMs, OS config, networking, scaling, etc is hidden away. However it’s worth understanding a little of what is going on; behind the scenes App Services are Windows VMs running IIS. Another part of App Services you need to be aware of is called Kudu, which you can think of as a hidden admin portal for your app, allowing you to do various management tasks, such as access a remote console, view logs and processes, edit files and of course deploy your code. Kudu is opensource and more info can be found on Github
App Services supports a range of dev platforms, such as .NET, PHP, Java, Python and of course Node.js. Some of these like .NET & PHP are trivial to run under IIS, Node.js (which we’ll call just ‘Node’ from here) is a little different.
Node is a funny platform, unlike .NET, PHP, Java etc, it doesn’t run hosted inside an web/app server, your code is the webserver. In many cases using something like Express to bind to a port, and accept HTTP requests directly. Node.exe will be the execution environment, but it’s not a webserver.
Under the covers App Services uses a “bridge” project called iisnode, which is a native IIS module used to host Node. Thankfully we don’t need to understand the details other than it’s there and App Services uses it.
All of this means there’s two things that need to happen for your Node code to run happily in an Azure App Service:
- At some point
npm installneeds to be run, either before or after deployment. This is a standard part of Node development, which populates your node_modules directory. This folder can be huge sometimes containing 10,000+ folders and files,which can present a challenge & slow down deployments.
- A valid
web.configneeds to be generated or deployed. It is this file that instructs iisnode and tells it which .js file to launch as the entry point to your app. I’ll cover the details/contents of this file later.
Interestingly not a single mention of either of these is made on the “Create a Node.js app in Azure Web Apps” getting started page, which led to much confusion for me further down the line.
How and when these two pieces happen boils down to how you deploy your code to your App Service. Which leads me to…
This is by far the simplest way to deploy your Node app to an Azure App Service, and also the method that employs the most “hidden magic”. Linking your App Service to git is easy, simply click on ‘Deployment Options’ when viewing your Web App in the portal. If deploying via a local git repo you will get a .git URL to point your repo at as a remote, with Github there will be a sync option within the portal.
When you do a git push it will trigger deployment automation task within Kudu, if you watch the output of the git push command you will see various things happening (the hidden magic I referred to earlier). Kudu is doing some clever stuff here, It will look inside your
package.json file and work out which is the main .js file for your app, as specified in the
scripts section as the
start script. It will use this and generate a valid web.config for you.
Next it will run
npm install --production to restore all the packages your app needs.
Here is a screenshot of the git output with the Kudu parts highlighted
This is all kinda great, you’re getting continuous deployment (build and release automation) for free, all built into the platform where your code will run. If I was being a DevOps purist there’s also a downside - you’re going straight from your code into a running deployed site, no chance to run unit tests, manage artifacts etc
One last thing before we move on, it’s worth being aware of the many configurable settings that Kudu has and in particular the
PROJECT setting which specifies which folder in your git repo to deploy rather than the whole thing from the root.
This is a slightly more managed deployment path where you have more control over what is happening. VSTS is a complex beast with a lot of features, I’ll be focusing on the Release aspect, and specifically the Deploy Azure App Service task
First time I tried to use this in VSTS to deploy my Node app to an App Service it was a failure. In trying to figure out why, lead me to discovering things like iisnode, web.config requirement and all the nice auto-magic that Kudu was doing to my previous git deployments.
In a nutshell; by default this task just dumps your files into your App Service, which is why it won’t work with Node applications without some settings changes.
Firstly getting the
web.config generated, this required not only ticking the fairly obvious tickbox but also providing a bunch of arcane undocumented parameters, as follows
I had to look in the sourcecode of the VSTS task to figure them out!
NodeStartFile parameter defaults to
server.js so can be omitted if that’s the name of your start file, also note it is not smart like Kudu so won’t examine your
package.json to get the correct filename
That leaves the
npm install part, with VSTS you have a choice:
- Pre deploy. Run
npm installas part of your build process and create a zip/artifact bundle which you then release with the Deploy Azure App Service task. This feels the most correct in terms of overall process, but has the downside of needing to transfer a lot of files with your release and to/from VSTS’s artifact store.
- Post deploy. Use the “Inline Script” option on the Deploy Azure App Service task. Which looks like this
Now we’re hitting the more “low cost” options. App Services supports a number of file transfer methods like FTP, OneDrive and Dropbox to get your stuff deployed. Here we get no automation, so you’re on your own.
web.config file you’ll need to bundle it with your code, you can use this sample. This isn’t a major downside as the contents are essentially static anyhow.
npm install you can do two things:
- Pre deploy. Run
npm installbefore you upload to the App Service. This has the snag that you’re transferring a tonne (often thousands) of files that essentially are not part of your app. Plus you’ll need to manage any differences between your
devDependenciesand your production packages
- Post deploy. Run the command manually using the Kudu remote console
A late update to this post, is the new Zipdeploy means to deploy to an app service. With Zipdeploy you simply HTTP POST a zip file containing your site/app over to Kudu, and bingo it gets deployed.
By default it assumes the zip contains a complete functioning site, so will require you to include
node_modules. However you can tell Kudu to carry out the same steps as it does when deploying from Git, if you set
SCM_DO_BUILD_DURING_DEPLOYMENT to true, this means you don’t need to worry about manually creating a web.config or zipping up all those node_modules files.
If you want to include the
SCM_DO_BUILD_DURING_DEPLOYMENT setting with your app, simply create a file called
.deployment with the following contents
.deployment file in your zip, and Kudu will do all the hard work of running
npm install and creating
web.config. Very nice.
One last issue you might see is not specifying the Node version you want to use, and your code will not start or will 500 error. If you created your Web App through the portal you won’t have a problem, but if you created it via an ARM template or the CLI you could trip over this. In order to set the Node runtime version, you need to define an app setting called
WEBSITE_NODE_DEFAULT_VERSION on your Web App. Apps created via the portal will have this set to version 6.9.1. Without this set, I found my deployed Node code would not start.
You can also specify this in your
package.json, in the
engines section, however I found the app setting method more reliable when deploying through VSTS
In order to find out what other versions are supported by your App Service, hit the following Kudu URL:
Here’s a quick summary of the different Node deployment options with App Services
- web.config - Created automatically by Kudu from the start script setting specified in your
- npm install - Run automatically post deployment by Kudu
- web.config - Generate with Deploy Azure App Service task and special options
- npm install - Automated choice of pre or post deployment
- web.config - Bundle with your app code
- npm install - Run manually
- web.config - Can be created automatically by Kudu from the start script setting specified in your
- npm install - Can be run automatically post deployment by Kudu
I’ll do a follow up post for Linux Web Apps soon, where things are kinda different :)