Scott Hanselman

Enabling Websockets for Socket.io Node apps on Microsoft Azure

November 3, '14 Comments [13] Posted in Azure | Diabetes | nodejs | Open Source
Sponsored By

Whoa my Blood Sugar is a CGM in the Cloud!NOTE: This is a technical post, I'll blog more about Nightscout later this week. Subscribe and watch for my take, or visit http://www.nightscout.info.

I'm running an application called Nightscout that is a node app with a MongoDB backend that presents a JSON endpoint for a diabetic's blood sugar data. I use my Dexcom G4 CGM (Continuous Glucose Meter) connected with a micro-USB OTG cable to an Android phone. An Android app bridges the device and POSTs up to the website.

Azure is well suited to run an app like this for a few reasons. Node works great on Azure, MongoLabs is setup in the Azure Store and has a free sandbox, Azure supports WebSockets, and *.azurewebsites.net has a wildcard SSL cert, so I could force SSL.

Enabling Websockets and Forcing SSL

So my goal here is to do two things, make sure Websockets/socket.io is enabled in my app because it's been using polling, and force my app to use SSL.

Setting up a node.js site on Azure is very easy. You can see a 3 minute video on how to do a Git Deploy of a node app here. Azure will see that there's a app.js or server.js and do the right thing.

However, because IIS and node are working together to host the site (IIS hands off to node using a thing called, wait for it, iisnode) you should be aware of the interactions.

There's a default web.config that will be created with any node app, but if you want to custom stuff like rewrites, or websockets, you should make a custom web.config. First, you'll need to start from the web.config that Azure creates.

Related Link:  Using a custom web.config for Node apps

Let's explore this web.config so we understand what's it's doing so we can enable Websockets in my app. Also, note that even though our project has this web.config in our source repository, the app still works on node locally or hosts like Heroku because it's ignored outside Azure/IIS.

  • Note that we say "webSocket enabled=false" in this web.config. This is confusing, but makes sense when you realize we're saying "disable Websockets in IIS and let node (or whomever) downstream handle it"
  • Note in the iisnode line you'll put path="server.js" or app.js or whatever. Server.js appears again under Dynamic Content to ensure node does the work.
  • I added NodeInspector so I can do live node.js debugging from Chrome to Azure.
  • Optionally (at the bottom) you can tell IIS/Azure to watch *.js files and restart the website if they change.
  • We also change the special handling of the bin folder. It's not special in the node world as it is in ASP.NET/IIS.
<?xml version="1.0" encoding="utf-8"?>
<!--
This configuration file is required if iisnode is used to run node processes behind
IIS or IIS Express. For more information, visit:

https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config
-->

<configuration>
<system.webServer>
<!-- Visit http://blogs.msdn.com/b/windowsazure/archive/2013/11/14/introduction-to-websockets-on-windows-azure-web-sites.aspx for more information on WebSocket support -->
<webSocket enabled="false" />
<handlers>
<!-- Indicates that the server.js file is a node.js site to be handled by the iisnode module -->
<add name="iisnode" path="server.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<!-- Do not interfere with requests for node-inspector debugging -->
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^server.js\/debug[\/]?" />
</rule>

<!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
</rule>

<!-- All other URLs are mapped to the node.js site entry point -->
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="server.js"/>
</rule>
</rules>
</rewrite>

<!-- 'bin' directory has no special meaning in node.js and apps can be placed in it -->
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>

<!-- Make sure error responses are left untouched -->
<httpErrors existingResponse="PassThrough" />

<!--
You can control how Node is hosted within IIS using the following options:
* watchedFiles: semi-colon separated list of files that will be watched for changes to restart the server
* node_env: will be propagated to node as NODE_ENV environment variable
* debuggingEnabled - controls whether the built-in debugger is enabled

See https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config for a full list of options
-->
<!--<iisnode watchedFiles="web.config;*.js"/>-->
</system.webServer>
</configuration>

Next, turn on Websockets support for your Azure Website from the configure tab within the Azure Portal:

Turn on Websockets in the Azure Portal

Now I need to make sure the node app that is using socket.io is actually asking for Websockets. I did this work on my fork of the app.

io.configure(function () {
- io.set('transports', ['xhr-polling']);
+ io.set('transports', ['websocket','xhr-polling']);

It turns out the original author only put in one option for socket.io to try. I personally prefer to give it the whole list for maximum compatibility, but in this case, we clearly need Websockets first. When will Websockets fall back if it's unavailable? What Azure website pricing plans support WebSockets?

  • Free Azure Websites plans support just 5 concurrent websockets connections. They're free. The 6th connection will get a 503 and subsequent connections will fallback to long polling. If you're doing anything serious, do it in Shared or above, it's not expensive.
  • Shared Plans support 35 concurrent websockets connections, Basic is 350, and Standard is unlimited.

You'll usually want to use SSL when using Websockets if you can, especially if you are behind a proxy as some aggressive proxies will strip out headers they don't know, like the Upgrade header as you switch from HTTP to Websockets.

However, even free Azure websites support SSL under the *.azurewebsites.net domain, so doing development or running a small site like this one gets free SSL.

I can force it by adding this rule to my web.config, under <system.webServer>/<rewrite>/<rules/>:

<rule name="Force redirect to https">
<match url="(.*)"/>
<conditions>
<add input="{HTTP_HOST}" pattern=".+\.azurewebsites\.net$" />
<add input="{HTTPS}" pattern="Off"/>
<add input="{REQUEST_METHOD}" pattern="^get$|^head$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}"/>
</rule>

Note the pattern in this case is specific to azurewebsites.net, and will take any Azure website on the default domain and force SSL. You can change this for your domain if you ike, of course, assuming you have an SSL cert. It's a nice feature though, and a helpful improvement for our diabetes app.

I can confirm using F12 tools that we switched to WebSockets and SSL nicely.

image

The whole operation took about 15 minutes and was a nice compatible change. I hope this helps you out if you're putting node.js apps on Azure like I am!


Sponsor: Big thanks to Aspose for sponsoring the feed this week! Working with Files? Aspose.Total for .NET has all the APIs you need to create, manipulate and convert Microsoft Office documents and many other formats in your applications. Start a free trial today.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb
Monday, 03 November 2014 08:20:31 UTC
Very useful, but I am already doing this. Yes the turning off websocket and turning it on from azure, did took quite a research when I was about to implement it. Now this blog post would be best place to refer it.
Monday, 03 November 2014 11:02:36 UTC
Sweet! Looks like a great enabler.
Dave
Monday, 03 November 2014 17:41:41 UTC
You missed a few steps from your guide: Get involved in Open Source today

  • Raise an issue / Suggest a Feature
  • Fork the Code, change it, then do a "pull request"


Nice that you found a simple settings change for a project relevant to you both personally and professionally though!
Jed
Monday, 03 November 2014 21:48:24 UTC
Jed - Thanks. I'm a member of the team. They knew it was coming and it's already been merged.
Scott Hanselman
Tuesday, 04 November 2014 13:29:19 UTC
Hi Scott! I was wondering if you still use LiveWriter to create your posts... and if yes, how you generate monthview, and other summary pages: do you do everything by hand, each time you create a new post?
Thanks.
Andrea
Tuesday, 04 November 2014 21:55:15 UTC
Maybe we need "Azure cookbook" book to have some ready to use scenarios like this
Sam
Wednesday, 05 November 2014 20:47:34 UTC
Can you define azure Standard vm? On azure price calculator
http://azure.microsoft.com/en-us/pricing/calculator/?scenario=full
they show an A0 for 15 a month under the Standard tab. So for 15 a month can have unlimited web socket connections?
Randall
Thursday, 06 November 2014 20:58:51 UTC
Oh, the both the free and shared tiers come with web sockets? They should update the pricing details page to reflect that. How many sockets does the shared tier come with?
Andrew Johnson
Saturday, 08 November 2014 12:16:47 UTC
Great Post Scott.
It was really helpful in explaining how node and IIS interact and why you need to disable websockets for IIS even though you are using websockets.
Thursday, 13 November 2014 04:03:13 UTC
I think these should be compiled for easy reference
Monday, 17 November 2014 19:24:34 UTC
@AndrewJohnson "unlimited" means as much as the server vm can handle.. you'll probably start to fall down somewhere between 500-5000 (depending on how much is actually being done beyond just handling an open connection). A larger instance should be able to handle around 50-100k connections per cpu with minimal overhead (basically hello world type of application. Realistically, you should consider 5k-10k connections per host CPU to be a realistic goal for real-world applications with moderate overhead with Node.js, though you will likely encounter other issues (max http connections to host default, and other max open connections/file handles type issues) before CPU load really becomes an issue.
Wednesday, 19 November 2014 07:03:12 UTC
Thanks for great article! I have issue when using your way with my site.
-Before apply your web.config, i can connect without https, no issue with CORS here
-After apply web.config, CORS issue is come.

Can u check again on it sir?
khanh vu
Thursday, 22 January 2015 22:14:38 UTC
Hey Scott,

Type 1 for 35 years. A1C is currently 5.6, so I am "guessing" pretty well. Was wondering if you knew of any of the pump companies who may be thinking of integrating a fitness tracker inside of a pump? We already have these things on us 24 hours a day.
Chris
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.