DEV Community

Discussion on: Hosting a Node.js application on Windows with IIS as reverse proxy

Collapse
 
jesben profile image
jesben

Hi Peter

Great article, thanks! :)

I also spent many hours on getting iisnode to run well.

Challenges I had with iisnode:

  • Node js app shuts down about an hour after if no one is using the site, even if I preload, autostart and always running turned on it it didn't help. So it took a few seconds to start up again for the first visit after shutdown.
  • When using websocket, only xhr polling works, websocket ws/wss is not working.
  • Unstable when using Windows authentication (A lot of http 400 errors).

I'm only using reverse proxy (ARR 3) now :)

I'm also a fan of PM2, also running it as a Windows service.

In my setup I need Windows Authentication and Websocket

Windows Authentication

Have tried with NodeSSPI is not working behind a reverse proxy.

URL rewrite is running before Windows authentication, so impossible to attach LOGON_USER in the header that way.

The solution here is:
ISAPI_Rewrite 3 LITE (Freeware)
helicontech.com/isapi_rewrite/down...

C:\Program Files\Helicon\ISAPI_Rewrite3\httpd.conf

RewriteBase /
RewriteCond %{REQUEST_URI} ^/.*
RewriteHeader X-Remote-User: .* %{REMOTE_USER}

E.g. for Express middleware

app.use(function (req, res, next) {
    if (req.headers.hasOwnProperty('x-remote-user')) {
        req['user'] = req.headers['x-remote-user'];
    }
    next();
});

The IIS site has Windows authentication enabled and with these providers: Negotiate, NTLM.

It gave me unfortunately these challenges when users visit the site for the first time (Tested with Chrome, Edge. In IE the error was constant)

401 
400 (X-ARR-CACHE-HIT=0&X-ARR-LOG-ID=7f1e3067-1a02-4405-b275-000f06952bc2&SERVER-STATUS=400)

This was driving me insane, then I turned off "Negotiate" as a provider, leaving only "NTLM" back and then the error was gone!

WebSocket

To use real websocket and not XHR polling, install IIS role "Websocket protocol" and add server variable "HTTP_SEC_WEBSOCKET_EXTENSIONS" to allowed server variables under URL rewrite.

Then add the server variable to your rule:

<rule name="ReverseProxyInboundRule1" stopProcessing="true">
    <match url="(.*)" />
    <serverVariables><set name="HTTP_SEC_WEBSOCKET_EXTENSIONS" value="" /></serverVariables>
    <action type="Rewrite" url="http://localhost:3000/{R:1}" />
</rule>
Collapse
 
petereysermans profile image
Peter Eysermans

Great info, thanks for taking the time to write it down.