Hosting Node.js projects in IIS virtual directories

Stas Demchuk

by Stas Demchuk on 09/23/2015

Hosting Node.js

While working on KAPTL's app preview mechanism, we ran into some issues with deploying Node.js projects to IIS virtual directories. 

One of the options of hosting Node.js apps in Windows is IISNode module for IIS.

In order to make a node app work in IIS virtual directory, you need to add the Web.config to the root of your project and add configuration sections for IISNode. Let's go through the configs in detail.

First, let's configure IISNode:

<iisnode node_env="PRODUCTION"
         nodeProcessCountPerApplication="1"
         maxConcurrentRequestsPerProcess="1024"
         maxNamedPipeConnectionRetry="100"
         namedPipeConnectionRetryDelay="250"
         maxNamedPipeConnectionPoolSize="512"
         maxNamedPipePooledConnectionAge="30000"
         asyncCompletionThreadCount="0"
         initialRequestBufferSize="4096"
         maxRequestBufferSize="65536"
         uncFileChangesPollingInterval="5000"
         gracefulShutdownTimeout="60000"
         loggingEnabled="true"
         logDirectory="iisnode"
         debuggingEnabled="true"
         debugHeaderEnabled="false"
         debuggerPortRange="5058-6058"
         debuggerPathSegment="debug"
         maxLogFileSizeInKB="128"
         maxTotalLogFileSizeInKB="1024"
         maxLogFiles="20"
         devErrorsEnabled="true"
         flushResponse="false"
         enableXFF="false"
         promoteServerVars=""
         configOverrides="iisnode.yml"
         watchedFiles="web.config;*.js" />

This block provides some sensible defaults for IISNode. If you need to override any of these, create a file called iisnode.yml in the same directory as Web.config and override specific parameters with new values.

Next, we need to add a handler so IIS knows where to send requests to. Usually, these should be sent to entry point for server-side code (usually app.js or server.js in the project root).

<handlers>
  <add name="iisnode" path="app.js" verb="*" modules="iisnode" />
</handlers>

After that, let's configure rewrites for our app:

<rewrite>
  <rules>
    <!-- Don't interfere with requests for node-inspector debugging -->
    <rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
      <match url="^app.js\/debug[\/]?" />
    </rule>

    <!-- serve static files from /public folder -->
    <rule name="StaticContent">
      <action type="Rewrite" url="public/{R:0}" logRewrittenUrl="true" />
      <conditions>
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
      </conditions>
      <match url="*.*" />
    </rule>

    <!-- All other URLs are mapped to the Node.js application entry point -->
    <rule name="DynamicContent">
      <conditions>
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True" />
      </conditions>
      <action type="Rewrite" url="app.js" />
    </rule>
    <rule name="SocketIO" patternSyntax="ECMAScript">
      <match url="socket.io.+" />
      <action type="Rewrite" url="app.js"/>
    </rule>
  </rules>
</rewrite>

Rewrites are tricky here. But the two most important ones are StaticContent and DynamicContent. They'll allow you to specify the endpoint for your static and dynamic requests. Dynamic requests should go to your application starting point (app.js in our case). IIS will handle static content if you specify the folder where it is located (/public in our case).

And finally, we'll let Node app know it's hosted in the virtual directory.

<appSettings>
  <add key="virtualDirPath" value="/node" />
</appSettings>

This is one of the key parts in the config. By adding this block to Web.config you will be able to use the value of virtualDirPath in your node code. The value of the parameter should be the relative route to the virtual directory in which the app is hosted. You should retrieve the value of this in the app via var virtualDirPath = process.env.virtualDirPath || ''; and prepend all your routes with it. Example:

var app = require('express')();
app.get(virtualDirPath + '/', function(req, res) {
  res.render('index', { virtualDirPath: virtualDirPath });
});

That's it! You should have your Node app working from IIS virtual directory!

Had any problems while making your Node app work? Let us know in the comments.