One does not simply run Node.js on Microsoft Azure
9We've been running Node.js on Microsoft Azure for about a year now on mediocre.com and recently launched meh.com using the same tech stack. Thought I'd share some of the tips, tricks, and things we've learned along the way.
You might be asking, "Node.js on Azure? Why?" I get this from time to time. I had a variety of reasons for going this route. Here's a big one: I've had a career's worth of experience building sites using .NET on AWS and wanted to try something different.
Let's set aside the reasoning behind running Node.js on Microsoft Azure for now and dive into the things you're gonna want to know if you end up going the same direction. If you're looking for the TL;DR here it is in meme form:
Docs
First, if you're going to run Node.js on Microsoft Azure you should read the docs at the Azure Node.js Dev Center. Over the past 18 months I've read them cover-to-cover dozens of times. They haven't changed much during that time which makes me wonder how much effort Microsoft is putting into Node.js on Azure these days. It's a pretty good set of docs though. They're certainly not comprehensive, but they're good getting started and tutorial material.
Support
I'll keep this part short. We're a Microsoft BizSpark member and I expected more help when I needed it. If you want to read more I've been fairly vocal about the mediocre support we've experienced.
Cloud Services vs Web Sites vs Virtual Machines
There's a few ways you can run Node.js apps on Azure. I would recommend using "Web Sites" when you can. It's the part of Azure where Microsoft is doing the most management for you, but you also have the least control.
Everything I'm going to cover here will be about "Cloud Services". We decided to run our public facing web applications and internal REST services using Cloud Services so that we could keep them inside a Virtual Network for security purposes.
Development
We do all our development on Mac OS X. The main reason I'm pointing this out is because Microsoft has created some tooling and support for Node.js inside Visual Studio which we don't use. Things might be easier with Visual Studio.
Build and deploy a Node.js application to an Azure Cloud Service
Once you're ready to get started working on a Node.js Azure Cloud Service, you'll probably land at this documentation. It's over two years old now, but it's where we got started.
The first thing you'll notice is that this documentation is written for Windows and PowerShell (not Mac). I created a Windows VM in Azure so I could run through the tutorial, then I pushed the files it created to GitHub and continued development on my Mac.
Follow all the steps in the tutorial and you'll end up with a working Node.js app running on an Azure Cloud Service.
IISNode
I mentioned the Azure docs for Node.js are about two years out of date. So are the PowerShell scripts and the dependencies they setup. You're going to want to update some things.
When you run Node.js on an Azure Cloud Service you're running Node.js on Windows in IIS using IISNode. The version that's installed by default is v0.1.21 which is over two years old. You'll want to upgrade to something like v0.2.14 before your app starts taking on traffic and runs into memory heap corruption issues like we did.
- Download the iisnode-full-v0.2.14-x64.msi installer from the IISNode GitHub repo
- Save iisnode-full-v0.2.14-x64.msi in the bin directory of your WebRole
- Modify your setup_web.cmd to install the MSI at deployment time: https://gist.github.com/freshlogic/f7db23fc883c0ad92c00#file-gistfile1-txt-L27-L30
node.exe
The version of node.exe that's installed by default is really, really old (v0.6.20). You'll probably want to use the latest v0.10.x version. Here's how we got this to work.
- Download the latest 64-bit Windows binary
- Save node.exe in the bin directory of your WebRole directory
- Modify your setup_web.cmd to copy the updated version of node.exe to the machine at deployment time: https://gist.github.com/freshlogic/f7db23fc883c0ad92c00#file-gistfile1-txt-L25
- Modify the Web.cloud.config file in your WebRole directory to set nodeProcessCommandLine="D:\node.exe": https://gist.github.com/freshlogic/cc7326042e80f29840b4#file-gistfile1-xml-L11
iisnode.yml vs Web.cloud.config
IISNode supports YAML configuration through an iisnode.yml file. It also supports configuration through the Web.cloud.config file. Since you need to have a Web.cloud.config file for IIS we do all our configuration there and ditched the iisnode.yml file to avoid any confusion.
Here's IISNode settings we changed in our Web.cloud.config file:
- debuggingEnabled="false" - turned off debugger for performance
- devErrorsEnabled="false" - turned off to get HTTP 5xx responses on errors instead of HTTP 200
- logDirectory="logs" loggingEnabled="true" - setup logging to a text file which has come in handy in certain debug scenarios
- node_env="production" - obvious
- nodeProcessCommandLine="D:\node.exe" - use the Node.js binary that we placed on the D: drive in our deployment package
- nodeProcessCountPerApplication="0" - in case we run on a machine that has multiple processors tells IISNode to startup a node.exe process for every processor
- promoteServerVars="HTTPS,REMOTE_ADDR" - Tells IISNode to to forward some IIS server variables in the form of HTTP headers to each request. We use the HTTPS server variable to help us with HTTP/HTTPS endpoints. As I answered on Stack Overflow, the trick is to let IIS handle the SSL termination for you so that your Node.js app only listens on HTTP (using process.env.PORT). We use the REMOTE_ADDR server variable because the X-Forwarded-For header doesn't work correctly out of the box and we patch it with this bit of middleware
Error Pages
IIS loves, loves, loves to be all up in your error pages.
But we have a little troll just waiting to sing his heart out when something goes terribly wrong
Here's what we did to tell IIS to chill, Winston... we'll handle error pages:
Deployment
This is the worst part of running Node.js on a Microsoft Azure Cloud Service in my opinion. Here's my top three reasons why:
- There's no way to deploy to an Azure Cloud Service from a Mac. The Cross Platform Azure CLI doesn't have this feature. The Cloud9 guys had something that no longer works with recent versions of Node. Your only option is to use PowerShell on Windows.
- The Publish-AzureServiceProject PowerShell command occasionally fails to build the "cloud_package.cspkg" that is uploaded to Azure during a deployment. You won't get a meaningful error message. You'll turn on the "Verbose" flag and learn nothing from it. I'll save you some time and tell you what's happening. Node.js apps are typically built using lots and lots of tiny, but highly compatible modules that are managed by NPM. Eventually, you'll use a module from NPM in your app that depends on another module which depends on another module which depends on another module. It's very easy for this to build a dependency graph of modules on disk whose file paths end up being greater than 260 characters which is longer than Windows can handle (even the latest version). I have two workarounds. First, run "npm dedupe" in your deployment script (https://gist.github.com/freshlogic/1e9fe62aa0d160a9ef93#file-gistfile1-txt-L19). Second, identify which modules end up creating the longest file paths on disk and install them at the root of your project before you install other modules (https://gist.github.com/freshlogic/1e9fe62aa0d160a9ef93#file-gistfile1-txt-L12-L14).
- It's slow. In our experience deployments usually take 15-30 minutes.
Final Thoughts
Can't say I'd recommend Node.js on Azure Cloud Services to other devs. As you can see, this was a pain in the ass to get all figured out. That said, we do enjoy working with other features of Azure. My personal favorite is the Azure Service Bus which is fantastic and we use it a ton. I wish Microsoft supported Azure Web Sites inside a Virtual Network the same way AWS supports Elastic Beanstalk inside a VPC.
Hoping we'll see more Node.js support on Microsoft Azure in the future, until then I hope these tips and tricks might save some devs a few hours.
- 9 comments, 5 replies
- Comment
Besides AWS and Azure what other cloud service would you want to use?
What are the pros/cons of running node via IISNode?
I see a lot of cons here, but I'm wondering if there are some pros you glossed over.
I honestly see little point in using Windows Server & IIS if you are not using C#.
Today, we are using a significant amount of CentOS servers and they are pretty simple to manage using Chef.
Azure has standard VM's right (Or are you forced to have them manage windows servers for you still)? You could probably have your build system create a VM image for each release and just rotate the new images in the load balancer for deployment (Linux servers boot fast).
Then if Azure has autoscaling, it would be able to still work.
@joneholland I think you're on the right track. It's not that we wanted to run Node.js via IISNode but we did want to run Node.js on an Azure Cloud Service rather than managing our own VMs, load balancing, deployment, auto-scaling, monitoring, patching, etc.
In a sentence here on this page those concerns are easy things to talk about, but you and I both know these are things that fail just as often as the application code you write. I want our team focused on writing ecommerce experiments more than they're focused on writing deployment code.
Totally fair. though there probably will come a point where the pain of IISNode will make it worth it. CM software has come a long way.
@Kevin For us, the list of requirements is something like:
AWS and Azure can do all those things. In my experience, the AWS compute features of their cloud (EC2, Elastic Beanstalk) are nicer to work with than Azure (Cloud Services, Website) but the AWS messaging features (SQS, SNS) aren't as nice as Azure Service Bus.
Awesome work. Sounds like it was a huge pain. Why not just go with something like Heroku for that kind of stack?
ah, sorry, didn't see your .net requirement.
we're also using node.js with azure and I cant really complain right now, a lot of the IIS error messages can be handled through web.config and also we solved the deployment issue by connecting azure with our continous integration jenkins which is in turn connected to our gitlab repository. so every time we push to the gitlab, jenkins runs our unit tests and pushes to azure deployment if all unit tests succeed.
also one tool we particularly like is the cross platform azure-cli that allows real time log insights of the node.js instance running on azure (azure site log tail )
the biggest problems we encountered so far were the idiotic woff/eot 404 issue with webfonts on azure (can be handled by web.config)
and somewhat mediocre performance compared to other hosting solutions we tried
Cheers
Thanks for the writeup! I'm not sure if something has changed with AzureWebRoles, but the ServiceDefinition.csdef has this setting:
Variable name="RUNTIMEURL" value="http://az413943.vo.msecnd.net/node/0.6.20.exe;http://az413943.vo.msecnd.net/iisnode/0.1.21.exe"
which seems to override the new version of node and iisnode. Then I ran into this recently, which sounds like the simplest way to request a particular version is to edit the packages.json engine variable.
http://azure.microsoft.com/en-us/documentation/articles/nodejs-specify-node-version-azure-apps/
Do you have any updated recommendations?
Thanks
I know this post is getting old now. But i have just started using Azure as my platform for my Node JS app. And i haven't run into any of these problems. I use git for deployment. If you have a decent service tier you have a lot of deployment slots.
I haven't got any of your nasty error pages.
Deployment has been as quick as on my own development machine.
I've even tried to push directly from development machine to git live branch and gotten my site live within 10 seconds.
My startup is still young and i might run in to similar problems in the future. But so far 3 months and no problems.
@Kiksen1987 sounds like you're using Azure Websites instead of Azure Cloud Services
@shawn Azure Websites in Resource Manager is definitely a different story.
Glad to hear about someone using Azure. I love the features of the platform as well. I am curious as to how you are using Azure Service Bus as I haven't ventured that far yet :)
Also, are you still using Cloud Services or have you moved to the new Web Apps/ARM platform?