How to setup iisnode with express? - node.js

I recently started working on nodejs. I created a simple nodejs api (with express) which connect to SQL server database and return result. After my development I had challenge how to host this node js api. I decided to host my api on IIS. I got different errors and in the end I was able to make it work. Thanks to different articles on internet.
Below are the steps I followed. May be this can help anyone who is new and trying to host nodejs in windows IIS.

I recently started working on nodejs. I created a simple nodejs api (with express) which connect to SQL server database and return result. After my development I had challenge how to host this node js api. I decided to host my api on IIS. I got different errors and in the end I was able to make it work. Thanks to different articles on internet.
Below are the steps I followed. May be this can help anyone who is new and trying to host nodejs in windows IIS.
Step 1: Install IISnode. Make sure to select correct bit version as per your machine. I was using windows 10 64 bit. I installed iisnode-full-v0.2.21-x64.msi
https://github.com/azure/iisnode/wiki/iisnode-releases
Step 2: Install URL rewrite module
https://www.iis.net/downloads/microsoft/url-rewrite
Step 3: For my use I created a new website in IIS with name "Node Web Site". This site is running on port 90. Point this web site to physical path where your Nodejs api is available.
Step 4: Provide node js api folder access to "IIS_IUSRS" group. You will get access error if don't provide access.
Step 5: Add a web.config file in your node js api folder. Add below code in your config file. This will tell IIS that server.js will be handled by IISnode.
Note: I have only one file in my project (server.js). If you have multiple files then you can add all those files here.
<configuration><system.webServer><handlers><add name="iisnode" path="server.js" verb="*" modules="iisnode" /></handlers>
</system.webServer></configuration>
Step 6: Add URL rewrite rule in your config file. This is required to make url user friendly. otherwise you need to provide .JS file path in the url. below is the final config file which I have in my application.
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="server.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<rule name="api">
<match url="api/*" />
<action type="Rewrite" url="server.js" />
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<add segment="node_modules" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
</configuration>
Before Rewrite section I was calling my application with url http://localhost/nodesample1/server.js
After rewrite url can be like
http://localhost/nodesample1/api
Step 7: Now you need to make changes in get call of express. you need to provide full path in get call.
for example before hosting application in IISNode my default get call code was like below snippet
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser());
app.get('/', function (request, response) {
response.write('running');
response.end();
});
But after IISNode hosting I had to change my get call like below
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser());
app.get('nodesample1/api', function (request, response) {
response.write('running');
response.end();
});
As I want me url to be like "http://localhost/nodesample1/api" I had to provide complete path in get call.
That's it.
This approach worked for me.

Related

Url Rewrite to another server for specific file (reverse proxy) does not work in Umbraco 8 site

I need to serve a script file from a third-party server as if it is coming from my own server. Should be a simple reverse proxy thing with url rewrite.
Prerequisites:
IIS has Url Rewrite 2.0 and ARR 3.0 installed.
What works:
when I set up an empty localhost website in IIS and add a simple rewrite rule like
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="ReverseProxyInboundRule1" enabled="true" stopProcessing="true">
<match url="localJs/proxiedScriptFile.js" />
<action type="Rewrite" url="https://thirdpartyserver.de/js/script.js" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
I can navigate to localhost/localJs/proxiedScriptFile.js and I get correctly served https://thirdpartyserver.de/js/script.js instead. So ARR and Rewrite is working.
What doesn't work:
When I add the same rewrite rule to the web.config of my existing Umbraco 8 website (on the same IIS), I get a HTTP 404.4 error, as if ARR does not work.
What I tried:
If in Umbraco 8, I change the rewrite to point to a local dummy file of
the same type, it works - the local dummy file is served. But the file off the third-party server is not.
Adding the rewrite path or url to
Umbraco.Core.ReservedUrls or Umbraco.Core.ReservedPaths does not
change the problem.
Any idea what I am facing here?
Kind regards!
Mikael
I solved my problem by using an OWIN middleware as a proxy, rather than using UrlRerwrite/ARR. This worked right away.
If someone comes up with a pure UrlRewrite/ARR solution, I am still interested. Here what works for me:
I found this ReverseProxyMiddleware for .Net Framework. Using this, my OwinStartup contains the following code:
public override void Configuration(IAppBuilder app)
{
// this must come before the base implementation so proxy kicks in before Umbraco
app.UseProxy(
new List<ProxyRule> {
// script proxy
new ProxyRule {
Matcher = uri =>
uri.AbsoluteUri.Contains("localJs/proxiedScriptFile.js")
,
Modifier = (req, user) => {
req.RequestUri = new Uri("https://thirdpartyserver.de/js/script.js");
},
RequiresAuthentication = false
}
},
r =>
{
}
);
base.Configuration(app);
}
Works like a charm. I post it here in case somebody else faces the same challenge.

Couldn't find the Socket running in the iis server in the iisnode webconfig to run socket.io

I am running IIS 10 and using iisnode I have to run my socket io (node) application . I have copied my ChatApp application inside www folder. I have added the web.config and added the below lines.
<handlers>
<add name="iisnode" path="index.js" verb="*" modules="iisnode" />
</handlers>
I have added the below socket connection
const io = socketio(server, { path: '/node/ChatApp/socket.io'});
And I am running my client in a different application. The connection string is
var socket = io('http://localhost', {path: "/node/ChatApp/socket.io"});
I couldn't connect the socket. I am getting following error
socket.io.js:7 GET http://localhost/node/ChatApp/socket.io/?EIO=3&transport=polling&t=MGsBu-c 404 (Not Found)
Let me know where I am missing? I know that I am missing the path somewhere. But I couldn't get whether my socket server running properly.
Note: I haven't add the rewirte url in the web.config.
But Without Iisnode I can able to connect and run the socket
Your socket should just be running on your server directly and not through your path.
So try on your client site either:
var socket = io('http://localhost');
or
var socket = io();

How and what to deploy Angular2 to IIS

Take for instance angular2-quickstart. What files need to be deployed and what settings need to be set to launch this web app from IIS?
This is a Typescript tutorial that I have opted to compile to JavaScript.
Setting up Angular 2 for me was quite an issue because the HTML5 routes (without a hashbang) weren't working.
To get an Angular2 project working on an IIS environment without serving it using the Angular-CLI (you still need it to build it!):
After you're finished with development on your project, you'll need to build (or compile) it to a different environment. If you need to set that up, read this.
The shortest build command you need is:
ng b
In your build folder (if you didn't add an external/different folder, this will be the 'dist' folder in your project), copy the contents to your IIS server.
Ensure the folder of your IIS server has the needed permissions for the IIS_IUSRS group and IUSR user to access it. (Right click on the folder -> Properties -> Security -> Edit -> Add, and type those in. You can click the 'Check Name' button to ensure it's the correct ones you're typing in)
The next issue you need to tackle is getting a web.config file to put in your server folder to fix routing issues.
If we were working with Apache, we would need an .htaccess, but for IIS, we're using a web.config. The one found here worked for me if your application is routing from the root directory of your server.
(Note: As reminded by #Demortes, this will require an additional module to be added to your IIS environment called URLRewrite)
This (web.config) file goes in the root directory of your server.
Hope this helps anyone who had similar issues to me :)
Cheers.
Download and install IIS rewrite plugin https://www.iis.net/downloads/microsoft/url-rewrite
Create application under default website.
Create a folder in c:\inetpub\wwwroot to host the application
After step 8 copy dist folder contents to c:\inetpu\wwwroot\
Before build in index.html change base href="/" to base href="//"
To skip steps 1,2 and 3 for every new build check out step 9 as alternative to step 8
Web config structure.
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Main Rule" >
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/<appname subfolder>/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Note: Create a Web.config in src folder and add a reference to it in angular-cli.json in assets section so that it gets copied over during each build. -
Otherwise you will have manually create this file every time ng build is used.
not applicable
In angular-cli.json put web.config in assets block
"assets": [
"assets",
"favicon.ico",
"Web.config"
],
In angular-cli.josn put custom css path example so that it will be packaged in styles..bundle.cs
"styles": [
"../node_modules/font-awesome/css/font-awesome.min.css",
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"assets/site.css",
"assets/page.css",
"assets/menu.css",
"styles.css",
"../node_modules/primeng/resources/primeng.min.css",
"../node_modules/primeng/resources/themes/omega/theme.css"
],
If you have custom scripts put those path under scripts section example
"scripts": [
"../node_modules/jquery/dist/jquery.js",
"index.js"
],
ng build --prod
Note: ng build --prod starts AOT (ahead of time compilation) by default in latest version of angular-cli
Note: ng build command deletes dist folder and recreates that folder every time you ng build command
Alternative build command:
ng build --prod --output-path 'C:\inetpub\wwwroot\<appname subfolder>' --base-href /<appname subfolder>'/
a- if you don't want to manually update base-href in index.html
b- if you don't want to copy dist folder and wwwroot folder of app.
Note1: Following command will only work if you open visual code (or any terminal app) with administrative privileges. Otherwise mkdir command to create output folder in wwwroot will fail.
Note2: You still need to update Web.config with . See step 4
Note3: Checkout slash / at both starting and end of --base-href /'/
Check direct quote from one of the posting. Not sure if changing security privileges of IIS_IUSRS group and IUSR user for ...wwwroot\
as described in one of the web links is required. May be it is not required but I am highlighting it over here for you to keep in mind.
Direct quote from another use : " Ensure the folder of your IIS server has the needed permissions for the IIS_IUSRS group and IUSR user to access it. (Right click on the folder -> Properties -> Security -> Edit -> Add, and type those in. You can click the 'Check Name' button to ensure it's the correct ones you're typing in)"
References :
- How and what to deploy Angular2 to IIS
- https://www.youtube.com/watch?v=K0XORWxG11k
The webapp itself needs no server intelligence, as it is just static files - web assets ( *.js, *.html files etc). The static files are what angular2-quickstart generates as output of its build process, which you run in your dev environment (probably locally on your personal computer). The dev environment will need node (+ npm). And infact, you can test this tutorial on your local dev environment without the need for any external server.
edit:
If u look in the package.json u can see it has lite-server:
"scripts": {
"start": "npm run lite",
"lite": "lite-server"
},
Lite server is a small server that simulates a simple (web) file server.
Lightweight development only node server that serves a web app, opens
it in the browser, refreshes when html or javascript change, injects
CSS changes using sockets, and has a fallback page when a route is not
found.
To give you an answer, to serve your app with IIS, you only need http://docs.asp.net/en/latest/fundamentals/static-files.html
I have created a small github project that has Angular2 current as of today (10/13/2016) that runs in IIS 7.5 with routing and under ng serve.
It does use the hash based URL strategy.
It uses angular-cli, the read me has details on how to setup under IIS or ng serve.
https://github.com/howserss/Angular2-IIS-sample-app
Angular 2 routing (with hash) will work without any issue on IIS. Just create default URL rewrite rule which will redirect all the requests to index.html file of your angular app. Rule will redirect all requests to index.html except for required js files and actual angular app urls (i.e. index.html or index.html#/{route-value}.
EX:
<rules>
<rule name="Default">
<match url="(.* ).js|index.html(.*)" negate="true" />
<action type="Rewrite" url="/index.html" />
</rule>
</rules>
Angular 2 routing (without hash) will not work with IIS.
In case of pure HTML application IIS will be routing the incoming request and it will redirect the request to error page if such page does not exist at that location.
In case of .Net MVC application you can create a default route to handle all the incoming request url's and redirect it to your angular index view.
Ex Route for MVC application:
routes.MapRoute(
name: "Angular",
url: "{*url}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { url = new AppFeatureUrlConstraint() }
public class AppFeatureUrlConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
if (values[parameterName] != null)
{
var url = values[parameterName].ToString();
if (url.StartsWith("angular/", StringComparison.InvariantCultureIgnoreCase))
return true;
else
return false;
}
return false;
}
}
Here is a nice and detailed explanation for deploying angular app in IIS. The summarized steps for publishing as a separate website are as follows:-
Create a web site in IIS, lets say the physical path you provided for this web application is C:\Publish.
publish you angular app using the below command:-
ng build --prod
After the application is built successfully copy and paste the contents of dist folder to C:\Publish folder.
Add web.config file to folder C:\Publish with following contents:-
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Angular Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
All done, now just go to IIS and browse your web-site, you will see it working.
after you build it, copy all files in dist fold put in a fold in your IIS server, it only contains html, css and js files, so just host it like a static website.
It works for any web server, no matter Apache, IIS or nginx.

deploying nodejs app to Azure via FTP does not work

I am trying out Azure with Node and using Wercker CI to build then deploy to Azure via FTP.
But it seems like I am having some trouble getting this to work. I am copying a server.js file along with a package.json and some other assets. But it looks like nothing runs the npm install command. Plus, I get a You do not have permission to view this directory or page. when reaching the site.
There is a web.config file with the following config:
<!--
This configuration file is required if iisnode is used to run node processes behind IIS or IIS Express. For more information, visit:
https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config
-->
<configuration>
<system.webServer>
<handlers>
<!-- indicates that the app.js file is a node.js application to be handled by the iisnode module -->
<add name="iisnode" path="./server.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<!-- Don't interfere with requests for logs -->
<rule name="LogFile" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^[a-zA-Z0-9_\-]+\.js\.logs\/\d+\.txt$"/>
</rule>
<!-- Don't interfere with requests for node-inspector debugging -->
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^\.\/server.js\/debug[\/]?" />
</rule>
<!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
<!--<rule name="StaticContent">
<action type="Rewrite" url="./app/assets/{REQUEST_URI}"/>
</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="./server.js"/>
</rule>
</rules>
</rewrite>
<iisnode watchedFiles="*.js;node_modules\*;routes\*.js;views\*.jade;middleware\*.js"/>
</system.webServer>
</configuration>
And the server.js is as simple as:
var http_1 = require('http');
var express = require('express');
var log4js_1 = require('log4js');
var morgan = require('morgan');
var split = require('split2');
// NOTE: Some of the features used are only available in ES6
// do not forget to start the server using `node --harmony` option so that everything will work properly,
// in case you use anything that is behind the staging flag.
// Check https://nodejs.org/en/docs/es6/#which-features-are-behind-the-es_staging-flag
// to see which features require the flag.
var app = express();
var APP_PORT = process.env.PORT || 5000;
var APP_PATH = __dirname + "/public";
// We will need to split the output from morgan into lines to avoid trailing line feeds,
// https://github.com/expressjs/morgan/issues/70.
var log = log4js_1.getLogger();
var log4jsStream = split().on('data', function (line) {
log.debug(line);
});
app.use(morgan('tiny', { stream: log4jsStream }));
// `__dirname` in this case will be `./dist/` since we start the server from there.
app.use(express.static(APP_PATH));
app.all('/*', function (req, res) {
res.sendFile(APP_PATH + "/index.html");
});
var server = http_1.createServer(app);
server.listen(APP_PORT, function () {
// console.log(`Express server listening on port ${APP_PORT}`);
});
//# sourceMappingURL=server.js.map
Finally, the package.json contains the necessary deps.
So I am just wondering, is there any way to deploy an app to Azure and trigger the npm install and start the web server?
I can see that if you do the deployment via Git, Kudu will do all of that for me. But I do not think that is an option for me while using Wercker to do the deployment. Also, I am compiling some TypeScript files during the CI builds and I do not want those in version control, so having a git repo where I need to store all the compiled files is also not an option.
I would really appreciate some input on how to handle this.
When deploying via FTP npm install will not be automatically run. In this case you can use console to run npm install
It’s a little confused according your description:
So I am just wondering, is there any way to deploy an app to Azure and trigger the npm install and start the web server?
I can see that if you do the deployment via Git, Kudu will do all of that for me. But I do not think that is an option for me
Generally, via Git to deploy your node app to Azure, it will run npm install automatically. What are specific requirements you prefer to if you wouldn’t like to use Git.
Currently I can’t reproduce your issue about Wercker. Does it occur errors when you deploy via GIT?
And according your comments with # theadriangreen, it seems you failed in npm install because of time out. If so, you can try to enable Always On setting of your Web App to prevent your site unload if they haven’t gotten any requests for a period time.
Additionally, if you still need some custom tasks after deployment, you can refer to Post Deployment Action Hooks to configure your custom deployment scripts.
When deploying via FTP npm install will not be automatically run. In this case you're going to have to include all of the dependencies in the folder that you deploy. So you can do that and deploy over FTP, or you can use git.
If you use git, you can add the files that you don't want deployed to your .gitignore, and then deploy them separately (i.e. put them in a blob).

node + socket.io fails on 'listen' Azure deployment

Nodejs server works like a champ locally. When deployed to Azure Web App, it fails with server error:
isnode encountered an error when processing the request.
HRESULT: 0x6d HTTP status: 500 HTTP subStatus: 1013 HTTP reason:
Internal Server Error You are receiving this HTTP 200 response because
system.webServer/iisnode/#devErrorsEnabled configuration setting is
'true'.
...
No real info here, so turned to the logs... where I see:
Fri Jul 24 2015 01:17:32 GMT+0000 (Coordinated Universal Time):
Unaught exception: TypeError: Object
\.\pipe\b9a229c1-7e20-4d2a-9f2d-fec75412cede has no method
'listeners'
at Server.attach (D:\home\site\wwwroot\node_modules\socket.io\node_modules\engine.io\lib\server.js:358:26)
at Function.attach (D:\home\site\wwwroot\node_modules\socket.io\node_modules\engine.io\lib\engine.io.js:124:10)
at Server.listen.Server.attach (D:\home\site\wwwroot\node_modules\socket.io\lib\index.js:226:21)
at new Server (D:\home\site\wwwroot\node_modules\socket.io\lib\index.js:51:17)
at Function.Server (D:\home\site\wwwroot\node_modules\socket.io\lib\index.js:39:41)
at Object. (D:\home\site\wwwroot\server.js:11:17)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
Tracing that back, I think the line of interest is:
at Object. (D:\home\site\wwwroot\server.js:11:17)
In the nodejs server code:
var socket = io.listen(process.env.port || 3000);
So I'm guessing the failure is possibly due to versioning or something? I can't seem to get any socket.io app to work on azure web deployment as cloud service or cloud app.
Anyone else?
Can you post the rest of your code? The initialization of your io variable is important to understanding what went wrong.
Your code should look something like this when initializing if you are using Express 4
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
// Get the port that we should be listening on
server.listen(process.env.PORT || 8080);
Inside your config, when using IISNode you need to specify that you are using Socket.io by adding the following to your <handlers> element in your Web.config:
<add name="iisnode-socket.io" path="server.js" verb="*" modules="iisnode" />
Additionally, we need to let IISNode know how to direct our Socket.io requests by adding a new rewrite rule:
<rewrite>
<rules>
<rule name="SocketIO" patternSyntax="ECMAScript">
<match url="socket.io.+" />
<action type="Rewrite" url="server.js"/>
</rule>
</rules>
<rewrite>
Also check and see if the socket.io package properly installed on your server instance.
Here's an answer I wrote about getting IISNode working in IIS using Socket.io and Virtual Directory usage as well.

Resources