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!');
});
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.
Add a new rule and select the Reverse Proxy
template.
Enable proxy functionality when you are prompted for it.
Add the address of your node.js website, don't forget to include the port, to the reverse proxy rules.
Once the rule has been added, the reverse proxy configuration works.
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
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.
Top comments (117)
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?
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.
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?
Also, how do I attach an image here? LOL. I'm just a new member here :c
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.
Wow! Ok, so this is the error that I receive. Hopefully I've attached the image properly. Thanks for assisting me.
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.
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!!
Great, well done. I'm glad you figured it out.
@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.
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!
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?
Thanks, Peter!
Yes, when I use "localhost:3000/app.js" it works; returning "Hello world" to the browser.
It is strange that you append
app.js
to the end of the url. I would expect that the command to run your application isnode app.js
and that you access your application via the urllocalhost:3000
. Not vialocalhost:3000/app.js
, is this a typo?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.
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.
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.
Hi, I found this tutorial very useful with getting the production version of our React/Express app working. We can now access localhost:5000 via localhost and our external domain.
One issue I am having is that every time I do a new build on the dev server, I get this error: EPERM: operation not permitted, unlink 'F:\inetpub\wwwroot\build\web.config' and I have to delete the web.config file and add the rule again in IIS.
Is there a way to avoid this do you know?
Thanks.
Is there a reason why the build touches the web.config? The web.config is configure once and then forget. You could build your node.js application in another folder to avoid the build changing the web.config file for the reverse proxy.
I have not encountered this problem myself.
Yes because I have IIS pointing to the build folder to run the app. There is a reverseProxy URL rewrite rule set in IIS which gets saved in the build folder.
web.config in build folder looks like this...
thepracticaldev.s3.amazonaws.com/i...
Could it be moved into the root of the project..? Im not sure how to edit it to do this.
It might work if you move it into another folder and change the basic settings of the IIS website to the new folder? That way the node application can run via pm2 from the build folder and IIS is pointing to the other folder. The web.config is then never changed by the build.
OK thanks I will try this when I get a chance.
Another issue im having which you may be able to help with is that we use a Virtual Machine to host the front end of our website. After installing PM2 globally under my login (the one I use to log on remotely to start a session), I am finding that PM2 only runs once I start a new session because the servers are only available up until 10pm and then restart at 7am. This means I have to start a new session each morning before PM2 starts and therefore starts the Express server. Ive also tried installing PM2 as a dependency in my project but not having much luck with it. Thanks.
I am currently looking into this myself. There is a npm package but I still have to try it out myself. This Stackoverflow question might also give some answers.
Hey Peter -
Having a new issue I wonder if you can help with.
When I change the code of my "sign_in.js" file, then go to the site, the old "Hello World" coming up. I'm betting I have something misconfigured. Hoping you are up for looking at this stuff:
ecosystem.config.js:
and for PM2, here's an image:
clearsay.net/images/2019-09-05-pm2...
I'll also try to use their "upload image" option here that didn't work in the past for me.
Did you already figured it out? I have not encountered this problem before. Maybe kill all the processes and just start the
sign_in.js
app and test what IIS is serving? You probably already tried it but I would start with the simplest case and try to get it to work.Totally unrelated but you can name your applications in pm2 when you start them with the
--name <app_name>
parameter. It makes it easier to identify them.The image upload worked.
Hey Peter -
I didn't. Then I realized - after having some other issues with Node.js and then studying Python some - that I would switch gears and learn Python instead. Proved to be easier to set up on Windows Server AND easier to write code in.
Thanks for checking in!
Scott
Hey @scottermonk I need to serve flask APIs on HTTPS in windows server. Can you help me ? I am unable to find any solution.
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.
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.That'll do just fine as well! ;)
Can you help more on this steps.
Hi Peter,
This was the single best resource for quickly resolving/troubleshooting errors related to running a NodeJS app and another application both over SSL. Many other resources–even for Windows–point to using NGINX which wasn't required at all.
Thanks, much appreciated.
Thank you for the kind words, Kevin. Glad to hear that the post was helpful.
Really thank you Peter.
I still can't believe it's so easy to solved, I have struggling in so called iisnode for hours.
By the way, the rules and patterns can be used for reverse multiple requests, in my case I host dozens websites on express, but only one website in IIS with several rules and patterns to reverse proxy them all.
It's quite easy even compare with Nginx...
Glad it worked out for you.
Very interesting, are you using the rules and patterns to route the request to the correct node.js app based on the web address/domain name the user is requesting? I am curious how it works.
Yea, it's works like kind of gateway proxy.
I have about 10 sites host in node.js, each of them has different name like entity identity logger, so in server they look like 'localhost:9000/entity', 'localhost:9000/identity'.
Then is the magic part, in the IIS reverse rule I added some regex expression, basically it will match the request with '/entity' or '/identity', and the match result can be used in redirect action like that: 'localhost:9000/{R:1}', so I am able to host as much as possible app in node.js, and just host a website with the specify regex expression for reverse all requests.
Hello Peter,
What a great article, thanks for sharing. PM2 is definitely nice to know. Everything works great and have now hosted my nodejs server on Windows.
However, I keep getting a 502.3 Bad Gateway whenever my request takes more than 2 minutes. So i'm guessing its a timeout issue. However, I can't seem to find where to change the timeout... Do you have any clue?
Hello Ayman,
I haven't encountered this myself but I think you should try to determine where the timeout is happening. Is it IIS that is giving the timeout or is it node.js. Can you execute the request on the local machine directly to the node.js process? If it is giving a timeout then the first thing to do is increase the timeout for the node.js process.
Hi Peter,
I have a nodeJS app with a express server running on port 443. I followed your steps and my index.html seems to work using hostname:443 in the Url. but when i login and it redirects to home.html (as supposed to) page. But it starts using localhost:443/home.html once again. How to i get rid of the localhost:443 in the home.html pages as well?
I added a second reverse proxy rule with localhost:443/home.html... But didn't work
What else would i need to do to make the other pages in my app change as well ?
If you use IIS as a reverse proxy you should not see the port of the nodejs application in your URL. IIS forwards the request to the nodejs application without the user noticing. Port 443 is the default port for https connections, I would not use it as the port for the nodejs application. I recommend changing the port to a port that is not commonly used, somewhere in the 3000 range for example.
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.
Hi, I would have to try it out. If I have the time I'll do some testing.
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!
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?