DEV Community

Peter Eysermans
Peter Eysermans

Posted on • Edited on • Originally published at eysermans.com

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

Unfortunately a lot of companies are still stuck with Windows servers. Nobody ever got fired for choosing Microsoft, right. As a developer this can be frustrating because choosing a server technology is usually limited to ASP.Net. I have experimented with hosting Node.js applications on a Windows server by using iisnode. But it is a pain to get up and running, setting the correct permissions is a time consuming chore. Microsoft has taken control of the development of the project but I get the feeling it's not very active any more. There are several Stackoverflow questions where people just give up configuring it.

So I wanted to go another route. What if we could use the Node.js web server and use IIS as a reverse proxy to route traffic to the Node.js web server? We could ditch iisnode and hopefully have a more reliable solution for hosting Node.js web applications.

First we need a small test project, this hello world Node.js Express application will do:



var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello World!');
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});


Enter fullscreen mode Exit fullscreen mode

To be able to run this, you need to install Node.js on your server. Once it's installed, you can run the test application by opening a command prompt and typing node app.js. If everything goes well you should now be able to access the test application via http://localhost:3000 on your local server.

To configure IIS as reverse proxy you need to install the URL Rewrite extension and the Application Request Routing extension. The URL Rewrite extension allows you to define rules to enable URLs that are easier for users to remember and for search engines to find. The Application Request Routing extension enables scalibility features: load balancing, rule-based routing and more.

Once these extensions are installed, you can begin configuring IIS. Open the Internet Information Services (IIS) Manager by opening the run window and typing the inetmgr command. Select the site for which you want to set up the reverse proxy and open the URL Rewrite extension.

Open URL Rewrite extension

Add a new rule and select the Reverse Proxy template.

Add rule

Enable proxy functionality when you are prompted for it.

Enable proxy functionality

Add the address of your node.js website, don't forget to include the port, to the reverse proxy rules.

Add reverse proxy rules

Once the rule has been added, the reverse proxy configuration works.

Working reverse proxy

The last piece that's needed is a reliable way of running the Node.js application. Starting it via the command prompt and keeping the window open is not a durable solution. If someone logs on to the server and closes the window, the website goes down. pm2 is a Node.js process manager, it can be used to keep applications running. Installing pm2 is easy with npm:



npm install -g pm2


Enter fullscreen mode Exit fullscreen mode

Once installed, we can use these commands to manage our processes:

  • pm2 start app.js: start our Node.js application
  • pm2 stop: stop a running process
  • pm2 restart: restart a running process
  • pm2 list: list all running processes

pm2 can do so much more, check out their website for more info. My own blog is currently running on this setup.

This is a cross post from my own blog.

Oldest comments (117)

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
petereysermans profile image
Peter Eysermans

Are you running the node.js application via pm2 or are you testing it via a command prompt? Going on your error message, it looks like your node.js application is not running.

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
abhishekhingu profile image
abhishekhingu

how we can do window authentication for angular app that served from express application running behind proxy

Collapse
 
petereysermans profile image
Peter Eysermans

It's hard for me to point you in the right direction. Can you give some more information what exactly goes wrong? Do you have an error message?

Collapse
 
abhishekhingu profile image
abhishekhingu

I have created an angular 2 application. Now, these are the requirements for windows authentication.

1) If any user within the organization access this application, he should not get the login prompt and should be able to login directly into the application.

2) If any specific user within the organization tries to access the application, then he should get the specific role(Like admin, Manager) and able to login directly.

3) If any user outside the organization tries to access the application, he should get the login prompt.

Backend will also play the significant role. I have created rest API using node js and express. So will this passport package help in my case? I have implemented the passport.js on my node js rest API, but now how to validate that thing on the angular side.

I hope this text helps you to understand my query.

Thread Thread
 
petereysermans profile image
Peter Eysermans

I don't have experience with Windows Authentication in combination with passport.js. There are a lot of frameworks and parts you're mentioning so it is difficult to solve this in a simple reply. There is an NPM package which mentions passing the user from IIS to node but that uses iisnode: npmjs.com/package/passport-windows.... So I guess you need to find a way for IIS to pass that the user to node running via pm2. Let me know if you find a solution.

Collapse
 
jesben profile image
jesben

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!

Collapse
 
vigneshlaksh profile image
vigneshlaksh

Hey Peter , Thank you so much for this document. With this URL write I am unable to pull public folder of NODE JS application , is there any web config changes needed to pull complete application

Collapse
 
petereysermans profile image
Peter Eysermans

Not that I know of, except for some rewrite rules I don't have any other settings in my web.config file.

Collapse
 
abhishekhingu profile image
abhishekhingu

How can I host two different expressjs app using IIS

Collapse
 
petereysermans profile image
Peter Eysermans

I have not tested this out but the express js apps would both run on a different port. For example one app would run on port 3000, the other on port 3001. In IIS you'd have to create two websites with the reverse proxy settings from one website pointing to localhost:3000 and the other pointing to localhost:3001.

Collapse
 
jmanuel_velasco profile image
JManuel

Yes, this is exacly how it works.
You can have both API published from the same main domain as well.

your-api.domain.com/api1
your-api.domain.com/api2

By defining the reverse proxy rules in the same IIS site.

Collapse
 
nybondasto profile image
Tomas Nybondas

Thanks for this great article!

It filled one big gap in my puzzle... :) In turn, I'd like to share with you an article: "The easiest way to install a node.js script as a windows service" here: github.com/tallesl/qckwinsvc and here: npmjs.com/package/qckwinsvc

I think that would be a good solution to keep application running in a managed and standardized fashion on a Windows server. At least administrators would thank you for this! :D

With best regards, Tomas.

Collapse
 
petereysermans profile image
Peter Eysermans • Edited

Thanks for the suggestion, I like it. I've solved this by using a task in the Task Scheduler to restart pm2 whenever the server restarts. I use pm2 resurrect for this.

Collapse
 
nybondasto profile image
Tomas Nybondas

That'll do just fine as well! ;)

Collapse
 
balasani profile image
Raghavender Balasani

Can you help more on this steps.

Collapse
 
emilmarlo profile image
Emil Marlo Red

Hi Peter, I came across this post because I want to deploy my node app in our windows server. Luckily this article looks great for my requirement. I'm just having a difficulty with the configurations of the bindings of my site. May I look on your site bindings? Should it be the same with the port I'm running on my Node App?

Collapse
 
petereysermans profile image
Peter Eysermans • Edited

The bindings of your site should be on port 80 for http and port 443 for https. Setting the same port as your node.js app in the bindings will not work. The port of the node.js app should only be set in the reverse proxy rules of IIS as you can see in the screenshot of the article.

Collapse
 
emilmarlo profile image
Emil Marlo Red • Edited

Oh, I see. Thanks for replying Peter. However, I don't think that URL Rewrite is working fine for me because I get a DNS_fail error. I am sure that I have followed and installed ARR and URL Rewrite and included the inbound rule for my site. As you can see in the image below, I'm running my node express server on port 3030. How about the physical path? As far as I know, I should point it to the folder where it contains my app.js, node_modules, etc. right?

Thread Thread
 
emilmarlo profile image
Emil Marlo Red

Also, how do I attach an image here? LOL. I'm just a new member here :c

Thread Thread
 
petereysermans profile image
Peter Eysermans

Yes, the physical path is pointing to the folder where the application is. In my case there is a web.config file in there with some rewrite rules, for example a redirect from http to https. Maybe if I see the exact error I will get an idea of what the problem is.

Adding an image is a bit cumbersome, I had to search for it myself. First you upload the image via the 2nd button in the left bottom corner. Then you can reference the url you get next to the icon in markdown. But you have to write the markdown yourself, otherwise your image will not be included.

Thread Thread
 
emilmarlo profile image
Emil Marlo Red • Edited

Wow! Ok, so this is the error that I receive. Hopefully I've attached the image properly. Thanks for assisting me.

error

Thread Thread
 
petereysermans profile image
Peter Eysermans

This rather looks like a DNS problem. Is there a DNS record for rlcnodetesting.rlc.corp.jgsummit.com pointing to the IP of the server where IIS is running? And is the subdomain in the bindings of IIS itself on port 80?

I would turn off the reverse proxy first and point the IIS website to a physical path with a static HTML file. That way you can ensure that the IIS binding and the DNS settings for that subdomain are working. Once that is verified, you can add the reverse proxy and go from there. It will be easier to troubleshoot where the problem resides.

Thread Thread
 
emilmarlo profile image
Emil Marlo Red

Dude! I think it's working, my problem would be the DNS itself. I'll ask our network administrator regarding this. But definitely, the URL rewrite is working. I just made it blank on my hostname to make it work. Thanks so much!!

site-binding

Thread Thread
 
petereysermans profile image
Peter Eysermans

Great, well done. I'm glad you figured it out.

Thread Thread
 
amita_sharma_f092ff4eccdd profile image
Amita Sharma • Edited

@emilmarlo I am facing same issue. My nextjs app working if ip address is All Unassigned and host name is blank. But when I assign up address and providing host name it’s not working.
Please let me know if possible how you fixed the DNS issue.

Collapse
 
andreybushman profile image
Andrey Bushman

Hi Peter.

Thank you for your article. I have the problem with pm2 using. I described it here: stackoverflow.com/questions/573822...

Do you know how to solve it?

Thank you!

Collapse
 
petereysermans profile image
Peter Eysermans

I'm afraid I don't have a solution. I did some googling but only found the Stackoverflow question you already mention in yours. In that question there is also a link to a Github issue, but it is still unresolved.

Collapse
 
kirvt profile image
kirvt

Hi! Thnx for the article. Seems that there will be some troubles with res.redirect('example.com'). I've got succeed with res.redirect('../local_route'), but everything with external URIs not working.

Collapse
 
petereysermans profile image
Peter Eysermans

Hi, I would have to try it out. If I have the time I'll do some testing.

Collapse
 
vv619perf profile image
vv619-perf

Hi Peter,
We have configured the IIS server with pm2 for nodeJs and configured as suggested in the post but when we try to do a res.redirect('') from the nodeJs code, it's not allowing us to redirect.
For example, calling API URL api-example/redirect it should redirect to
angular-website/success?type=1 but the URL is shown as api-example/success?type=1
Thanks for any help you can give!

Thread Thread
 
petereysermans profile image
Peter Eysermans

Without code it's hard to determine the problem. Is the nodejs application redirecting to the internal URL instead of the actual URL that is used to access it via IIS?

Collapse
 
scottermonk profile image
ScotterMonk • Edited

Hi Peter -
Thank you for giving me hope!
I'm getting a 502 Bad Gateway error:
"Web server received an invalid response while acting as a gateway or proxy server."
Windows Server 2016.
Please see attached image of pm2 status of the app.
Oh and how do you determine that port of 3000?
Should I have put "localhost:3000" in that rule or the physical path to my app?
Thanks for any help you can give!

Collapse
 
petereysermans profile image
Peter Eysermans

Hi,

I can't see the image, I think you forgot to link it in your comment. Is the node application accessible on the server itself from localhost:3000? When exactly are you receiving that error?

The port is configured in node. The app.listen statement takes the port on which the node application will listen.

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

If you change that number, the application will listen and be accessible on a different port.

Collapse
 
scottermonk profile image
ScotterMonk • Edited

Hi Peter -
Thanks for responding to my last question.
OK... I started over. Reinstalled node.js on my Windows 2016 Server.
When I do "pm2 show," I see app.js is running.
"node app.js" worked great from the command prompt. As in, it outputs what it should, within the command prompt window.
I set up the reverse proxy rule in iis for my test site's domain name "amonkeymarket.com".
If you go to amonkeymarket.com/app.js, you will just see the code, not execution of the code. This happens whether I go there with a local browser on the server or remote.
Ideas?
THANK YOU!

Collapse
 
petereysermans profile image
Peter Eysermans

So the reverse proxy kind of works as you are seeing the app.js file which is part of the node.js application. Does it work if you directly go to the node.js application on the server? I mean opening a browser on the server and going to localhost:3000 (or the port you used), does that work?

Collapse
 
scottermonk profile image
ScotterMonk

Thanks, Peter!
Yes, when I use "localhost:3000/app.js" it works; returning "Hello world" to the browser.

Thread Thread
 
petereysermans profile image
Peter Eysermans

It is strange that you append app.js to the end of the url. I would expect that the command to run your application is node app.js and that you access your application via the url localhost:3000. Not via localhost:3000/app.js, is this a typo?

Thread Thread
 
scottermonk profile image
ScotterMonk • Edited

Oh sorry for the added confusion. It makes no diff whether I add that /app.js or not (just re-tested). I was doing so because I had a few .js files there to try different tests. Thanks for hanging with me on this, Peter! Deadline approaching and I'm worried.

Thread Thread
 
petereysermans profile image
Peter Eysermans

Unfortunately at the moment I don't have any more input to give you without being able to see the code and the configuration. Most of the time it helps to check every part independently but it looks like you double checked every part and setting. If I can help any further please let me know.

Thread Thread
 
scottermonk profile image
ScotterMonk • Edited

I hear you. Thanks for the amount you tried to help.
UPDATE: Got it working!
I had set up the URL Rewrite redirect rule wrong.
THANK YOU SOOO MUCH!
I was lost [in iisnode hell] before finding your article.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.