Enabling Websockets for Socket.io Node apps on Microsoft Azure
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:
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.
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.
About Newsletter
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!
Thanks.
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?
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.
-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?
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.
Comments are closed.