Monday, August 29, 2011

Hosting express node.js applications in IIS using iisnode

In my last two posts I introduced the iisnode project which allows hosting node.js applications in IIS on Windows, as well as shown how it integrates with the URL rewrite module. In this post I demonstrate how to run node.js applications that use the popular express framework in IIS.

Installing express on Windows

Node.js modules, including express, are typically installed using NPM. The bad news is that as of this writing NPM is not yet supported on Windows. The good news is that for simple cases one can use the ryppi.py script. Assuming you have Python installed, you can call:

ryppi.py install express

which will create the node_modules folder with the downloaded express library. You can check out the resulting layout here.

The code

A simple express application we will host in IIS looks like this:

   1: var express = require('express');
   2:  
   3: var app = express.createServer();
   4:  
   5: app.get('/node/express/hello/foo', function (req, res) {
   6:     res.send('Hello from foo! [express sample]');
   7: });
   8:  
   9: app.get('/node/express/hello/bar', function (req, res) {
  10:     res.send('Hello from bar! [express sample]');
  11: });
  12:  
  13: app.listen(process.env.PORT);

Two key aspects to call out that may be different from your bread & butter express app are:

  1. The path specified in app.get calls must be the full path of the request (lines 5 and 9). When your app is hosted in IIS, depending on the configuration you may not necessarily own the entire namespace over port 80. Like in the example above, your IIS hosted express application may reside in the ‘express’ folder of  the ‘node’ virtual directory, and only own the subordinate URL namespace.
  2. Similarly to a non-express node.js app hosted in iisnode, the listen port is provided by IIS through the PORT environment variable. When you start your listener (line 13), this is the port you should specify.

The web.config

I talked about using the URL rewrite module for regular node.js applications before, and URL rewriting is perhaps even more relevant in case of URL-conscious express apps. The web.config below allows the express application saved in hello.js to receive HTTP requests directed at all URL paths subordinate to the ‘hello’ path component, as configured in lines 20-27:

   1: <configuration>
   2:   <system.webServer>
   3:  
   4:     <!-- indicates that the hello.js file is a node.js application 
   5:     to be handled by the iisnode module -->
   6:  
   7:     <handlers>
   8:       <add name="iisnode" path="hello.js" verb="*" modules="iisnode" />
   9:     </handlers>
  10:  
  11:     <!-- use URL rewriting to redirect the entire branch of the URL namespace
  12:     to hello.js node.js application; for example, the following URLs will 
  13:     all be handled by hello.js:
  14:     
  15:         http://localhost/node/express/hello/foo
  16:         http://localhost/node/express/hello/bar
  17:         
  18:     -->
  19:  
  20:     <rewrite>
  21:       <rules>
  22:         <rule name="hello">
  23:           <match url="hello/*" />
  24:           <action type="Rewrite" url="hello.js" />
  25:         </rule>
  26:       </rules>
  27:     </rewrite>
  28:  
  29:     <!-- exclude node_modules directory and subdirectories from serving
  30:     by IIS since these are implementation details of node.js applications -->
  31:     
  32:     <security>
  33:       <requestFiltering>
  34:         <hiddenSegments>
  35:           <add segment="node_modules" />
  36:         </hiddenSegments>
  37:       </requestFiltering>
  38:     </security>    
  39:     
  40:   </system.webServer>
  41: </configuration>

One other aspect worth pointing out is request filtering. Remember the express application relies on the express library installed in the node_modules directory? You probably don’t want the contents of this directory to be served by IIS in any shape or form, and you can express (sic!) that desire by adding it to hidden segments list (lines 32-38).

Voila!

Your IIS-hosted express node.js application behaves like expected:

image

image

So where can I get iisnode again?

Everything you need to get started is at https://github.com/tjanczuk/iisnode. Make sure to check out the express sample. Feedback welcome!

10 comments:

  1. i have created a port of ryppi to c# which can be found at https://github.com/prabirshrestha/nji

    you can now type
    nji install express

    ReplyDelete
  2. Any idea what could be my problem here: http://stackoverflow.com/questions/9904897/iisnode-iis7-5-405-method-not-allowed-when-performing-put-request
    Thx

    ReplyDelete
  3. How would I configure the rewrite so that a request to "/node" would be rewritten so that my node app sees "/" or ""? There doesn't seem to be a way to do this. I'd hate to change all my routes to have "/node" prepended in my node app.

    ReplyDelete
    Replies
    1. In general this may be not be a good idea. If your app is configured to generate responses to the client which contain URLs relative to the request URL (as is oftentimes the case with MVC apps), the browser may get confused, since its URL is different from the URL on the server.

      Perhaps the best way to host node.js applications in IIS using iisnode is to dedicate an entire IIS Web Site to the application as opposed to creating a virtual directory or an application within a Web Site.

      Delete
    2. Actually i have same concern. Even if I host iisnode under VirtualDirectory I not want to specify it in every routes. Especially if my aplication is installable, and i can't know before how it will be named.

      Maybe iisNode can provide some info about VirtualDirectory where it is running? kind of Request.ApplicationPath in Asp.Net, than i can use it to prefix. or use same notations "~/"

      Delete
  4. Hi Thomasz,

    Very good and helpful post, it works for me! But I can't get it working with https. We have a SSL certificate installed on our server and in the IIS manager I have added my iisnode folder (www) as an application under the secure website. NodeJS without the express framework works fine, but all my express applications gets the "404 - File or directory not found".

    I thought it might be a problem with the port listening, so changed it from process.env.PORT to 443 (which is default https port), then I got the following error message from iisnode: "Application has thrown an uncaught exception and is terminated: Error: listen EACCES".

    I have been struggling with the problem for way to many hours now :(
    If you could give me an idea or just a hint to what the problem might be, I would appreciate it a lot!? Thanks.

    ReplyDelete
    Replies
    1. You should be using process.env.PORT. Does the same express application work fine over HTTP as opposed to HTTPS?

      Delete
    2. Alright, it seems to be working (https/http) when I change the physical path of my secure website (in the IIS manager) to the iisnode www folder. But when adding the same folder as an virtual directory and converting it to an application (under the website), I get the 404 on all my express applications (https/http). :/

      I'm not that familiar with the IIS and can't figure out if I doing it wrong or it's a bug. But at least I can get it to work now :)

      Thanks!

      Delete
  5. I'm new to this and curious why I am able to access sample applications locally, but not via a www request. I have iisnode sitting on a Windows IIS 7.5 Server, on Windows 2008 RC2.

    I can test them adaquately locally. However, when I attempt a remote connection I end up with the following error:
    Handler "iisnode" has a bad module "iisnode" in its module list

    I'm obviously missing something either in ignorrance or lack of understanding.

    so again:
    http://tractools.com/node locally functions for all examples
    http://tractools.com/node remotely does not...

    thoughts?

    ReplyDelete
  6. Hi Tomasz,

    I have deployed NodeJS sample app in accordance with http://expressjs.com/guide.html instructions.

    It is running locally just fine, but when I try to run it through IIS and IIS Node as described in http://tomasz.janczuk.org/2011/08/hosting-express-nodejs-applications-in.html,
    I am getting "HTTP Error 403.14 - Forbidden".

    My web.config is following:























    Any ideas?

    Thanks.

    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.