Thursday, November 1, 2012

How to use WebSockets with node.js apps hosted in iisnode

Note: if you are interested in hosting socket.io WebSocket applications in IIS using iisnode, check out the more recent post at http://tomasz.janczuk.org/2013/01/hosting-socketio-websocket-apps-in-iis.html

The recent release of iisnode v0.2.0 enables using WebSockets in node.js applications hosted in IIS 8.  This functionality requires Windows Server 2012 or Windows 8. To read more about iisnode in general check out my previous post.

Getting started

After installing iisnode v0.2.0, get a sample WebSocket application from https://github.com/tjanczuk/dante (if you are not a Git person, you can also download a ZIP):

git clone https://github.com/tjanczuk/dante.git

Next, download the node.js dependencies and set up an IIS application in IIS 8 that points to the downloaded code:

npm install
setup.bat

Lastly, navigate to http://localhost/dante/server-faye.js and enjoy Dante’s Dive Comedy, Canto 1, streamed to you over WebSockets though IIS and iisnode, once stanza every 2 seconds:

image 

Under the hood

If you have a closer look at server.js, you will notice the application uses the faye-websocket module to establish a WebSocket server, just like a self-hosted node.js WebSocket application would:

var WebSocket = require('faye-websocket')
, http = require('http');

var server = http.createServer(handler);

server.addListener('upgrade', function(request, socket, head) {
var ws = new WebSocket(request, socket, head);
// ...
});

function handler (req, res) {
// ...
}

server.listen(process.env.PORT || 8888);

In fact, you could take this application and run it self-hosted using node.exe without any changes at all.

The iisnode module uses the functionality enabled in IIS 8 on Windows Server 2012 and Windows 8 to expose the HTTP Upgrade mechanism to the node.js application. Modules like faye-websocket, ws, or socket.io implement the WebSocket protocol on top of the HTTP Upgrade mechanism and expose WebSocket functionality to the application.

Using WebSockets in a node.js applications running in iisnode requires that – contrary to what one would expect – websockets are disabled in web.config:

<configuration>
<system.webServer>
<webSocket enabled="false" />
<handlers>
<add name="iisnode" path="server-faye.js" verb="*" modules="iisnode" />
</handlers>
</system.webServer>
</configuration>

This is required because IIS 8 provides its own implementation of the WebSocket protocol that builds on top of the HTTP Upgrade mechanism. If the IIS 8 WebSocket module remained enabled, it would conflict with the WebSocket implementation provided by the node.js application itself in the form of one of the node.js modules, e.g. faye-websocket, ws, or socket.io. The IIS 8 WebSocket module is used to enable WebSocket functionality in ASP.NET applications.

So where does it leave you?

The release of iisnode 0.2.0 closes the last major functional gap between self-hosting and IIS hosting node.js applications on Windows: the availability of WebSockets. You can now host your socket.io application in IIS 8 using WebSockets as opposed to falling back to HTTP long polling. Note that WebSocket functionality is only supported on IIS 8 running on Windows Server 2012 or Windows 8. WebSocket on!

15 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Is there any way to make websockets in node work on IIS *Express* 8.0 on Windows 8? IIS Express 8.0 says it has WebSocket support but points to the .NET implementation of it. I tried adding webSocket enabled=False in my web.config, but when I try to open a new WebSocket to ws://localhost in IE10 and Chrome I just get an error event followed by a close event with code 1006.

    ReplyDelete
  3. Hi,

    I am new to socket.io and iisnode. I've been looking around for an example to setup socket.io in iisnode. I was able to setup a site in IIS and route requests for the the app's server.js, which contains socket.io initialization code, to an iisnode module. However, I haven't been able to get the "/socket.io/socket.io.js" loaded into the page so that I can connect the socket setup on the server.

    I've tried using UrlRewrite like what's shown below, but it seems like the script has other dependencies that need to be loaded first.











    I'm running out of luck and pulling my hair out. I really hope I could find some help here. All I want is to setup a socket server running in iis and a browser client talking to the server via a socket initialized by the server.

    Thanks a lot in advance for any help.

    ReplyDelete
  4. Hey, Tomek. I seem to get this error no matter what I do: "Unable to establish WebSocket connection to ws://192.168.1.64/dante/server.js/ws"
    I am running Windows Server 2012 (IIS8), latest node.js and have installed iisnode and turned on the websockets feature for IIS.

    I will say, when I have websockets disabled in the web.config I get this error:

    This configuration section cannot be used at this path. This happens when the section is locked at a parent level. Locking is either by default (overrideModeDefault="Deny"), or set explicitly by a location tag with overrideMode="Deny" or the legacy allowOverride="false".

    It doesn't seem to matter whether it's in the dante folder webconfig, the wwwroot webconfig, or if there is no wwwroot webconfig and in the dante config.
    When I remove it, it goes back to the "unable to establish..."

    Can you please help? :)

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. First of all, the section of web.config that _disables_ web sockets must be _present_ for the sample to work. The reason IIS rejects this section is that modifying its value must be disabled in the applicationHost.config in your system. Go to %systemdrive%\windows\system32\inetsrv\config\applicationHost.config, find a line like <section name="webSocket" overrideModeDefault="Deny" /> and change it to say overrideModeDefault="Allow". This should help. If it does not, please file an issue at https://github.com/tjanczuk/iisnode/issues/new.

      Delete
    3. This comment has been removed by the author.

      Delete
    4. What finally removed the error was "c:\windows\system32\inetsrv\appcmd.exe unlock config -section:system.webServer/webSocket"
      Run from the cmdline.
      Now I don't receive that error but still get "Unable to establish WebSocket connection to ws://localhost/dante/server.js/ws"

      Delete
    5. Sorry don't mean to spam the blog, but is there anything else I could possibly try or look at? The log seems empty, but I am new to node so perhaps there's somewhere I'm not looking?

      Delete
    6. This comment has been removed by the author.

      Delete
  5. This comment has been removed by the author.

    ReplyDelete
  6. Hi,

    Great job on the iisnode and the new support for websockets. Got the wyse-socket example working no problem. Can't seem to get even a simple socket.io example working though. Do you have a simple socket.io example of know of one? I have tried many things for several hours, just missing some piece.

    Regards,

    Tim

    ReplyDelete
    Replies
    1. I am about to produce a blog post specifically on socket.io in iisnode as many people are having difficulty setting it up. The key aspect to get right is hosting your site in the root of the IIS Web Site (as opposed to a virtual directory), which plays better with socket.io defaults.

      Delete
    2. OK, the post about using socket.io apps in IIS using iisnode is out at http://tomasz.janczuk.org/2013/01/hosting-socketio-websocket-apps-in-iis.html

      Delete
  7. Tomasz,

    Thanks for such a quick reply. Haven't checked it out just yet, doing that next, but thanks in advance. Very much appreciated. If you have a donations link, let me know.

    Regards,
    Tim

    ReplyDelete

My Photo
My name is Tomasz Janczuk. I am currently working on my own venture - Mobile Chapters (http://mobilechapters.com). Formerly at Microsoft (12 years), focusing on node.js, JavaScript, Windows Azure, and .NET Framework.