HTTP ERROR 400.605. Deploying NodeJS app on IIS - node.js

I've got error during deploying my app to IIS Server. I use URL Rewrite and IISNode. I gave all permissions to IUSR and IIS_IUSRS, and I went throught a lot of errors, but I can't go through this one. I will be very grateful for your help.
I've got this error
My web.config file looks like:
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="src/app.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<rule name="app">
<match url="/*" />
<action type="Rewrite" url="src/app.js" />
</rule>
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://localhost:8080/{R:1}" />
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<add segment="node_modules" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
</configuration>
My app.js file looks like:
const express = require('express');
const cors = require('cors');
const app = express();
app.get('/', (req, res, status)=>{
return res.status(200).json({
"message": "Hello world!"
});
});
app.use(cors());
app.use(express.json());
app.listen(8080, () => {
console.log('App listening on port 8080')
});

From the analysis of the error information, it can be determined that the problem is caused by the abnormal request of the ARR module, mainly because of the syntax error of the URL rewriting rule, which will cause this 400.605 error. It is recommended to use the exclusion method, first disable all ARR rules, and then gradually sort out the rules with grammar problems.
Here is the same question you can use as a reference: ARR The request cannot be routed because it has reached the Max-Forwards limit. The server may be self-referencing itself in request routing topology.

Related

Serve Angular client and Express Sever on IIS without breaking urls

I used angular on the client-side, and nodejs on server-side, when running them using webstorm IDE they behave as expected but now I'm trying to put them on is and I'm encountering some troubles.
My main goal is to make just the client and server work together so if you have another suggestion which I have not tried, please comment.
In the IIS I had to put both server and client under the same URL (obviously) so I have deployed my angular app and copied the content of the dist folder into folder name "wwwroot" to my server (express).
Here is my code:
app.js files:
app.use(express.static(__dirname + '/wwwroot'));
app.post('/home', (req, res) => {
// some content here
});
app.get('/home', (req, res) => {
// some content here
});
const server = http.createServer(app);
server.listen(port, () => console.log('Listening to port: ' + port));
my web.config file:
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="app.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<rule name="nodejs">
<match url="(.*)" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="/app.js" />
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<add segment="node_modules" />
<add segment="iisnode" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
</configuration>
Now, it would work just fine but I have 1 main problem which I can't solve when I'm trying to reload a page via a URL,
e.g. "http://www.automationcompare.com:4040/home;urlId=23119.06799149191"
then I get: Cannot GET /home;urlId=23119.06799149191.
I think the server should be set up to return the base HTML page no matter the url. You need to use url rewrite rule like below sample:
<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="./index.html" />
</rule>
</rules>
</rewrite>
</system.webServer>
For further information about your problem, you can refer to this post. I think it is similar to your problem.

Disable directory browsing in Nodejs, Azure

I'm trying to disable directory browsing in node, hosted on Azure.
This is my root folder and I want to disable browsing.
The following is my index.js file
const express = require('express');
const publicweb = './';
const app = express();
app.use(express.static(publicweb));
app.disable('x-powered-by');
console.log(`serving ${publicweb}`);
app.get('*', (req, res) => {
res.sendFile(`index.html`, { root: publicweb });
});
const port = process.env.PORT || '3500';
app.listen(port, () => console.log(`API running on localhost:${port}`));
I do not want the files to be accessible from the front-end application.
You can try by creating a web.config, under the hood Azure uses IIS to serve your app
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<webSocket enabled="false" />
<handlers>
<add name="iisnode" path="app.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^app.js\/debug[\/]?" />
</rule>
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
</rule>
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="app.js"/>
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough" />
<iisnode watchedFiles="web.config;*.js" debuggingEnabled="false" />
</system.webServer>
</configuration>

Hosting node js website to Azure. Default path / not working

I have a node js website which I am deploying to the azure server using visual studio code. The following is my code at server.js
var express =require('express');
var bodyParser=require("body-parser")
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
var nodemailer = require("nodemailer");
var port=process.env.PORT || 3000;
app.use(express.static(__dirname + '/public'));
app.get('/',function(req,res){
console.log('hello from server');
res.render('./public/index.html');
});
I deployed the website to an azure app service and the url always expects the index.html to be added to it to work. for e.g https://abc.azurewebsites.net does not work but https://abc.azurewebsites.net/index.html works. How do I remove the index.html from the url?
My azure folder structure is site/wwwroot/public/all html files.
Can anyone please suggest a solution
Update:
web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<webSocket enabled="false" />
<rewrite>
<rules>
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="public/index.html"/>
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
</configuration>
Original Answer:
Just add a file named .htaccess to the root directory('/site/wwwroot'), and this is the content of the file:
DirectoryIndex public/index.html
After that, default of your web app will change to 'public/index.html'.

HTTPS issues in azure

I imported the git socket.io chat room project! The code works normally with http = require ('http') but when exchanging for https = require ('https') my server responds with error 500 http
var express = require('express')
, app = express()
// , http = require('http')
, https = require('https')
, fs = require('fs')
, privateKey = fs.readFileSync('HTTPS_Permissions/key.key', 'utf8')
, certificate = fs.readFileSync('HTTPS_Permissions/cert.cert', 'utf8')
, credentials = {key: privateKey, cert: certificate}
, httpsServer = https.createServer(credentials, app)
// , httpServer = http.createServer(app)
, io = require('socket.io').listen(httpsServer)
//, port = process.env.PORT || 8080
, port = process.env.PORT
httpsServer.listen(port, function () {
console.log('Server listening on port %d', port);
});
//httpServer.listen(port);
// routing
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
I followed the project you shared in the comment,it works on my side.
web.config
<?xml version="1.0" encoding="utf-8"?>
<!--
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>
<!-- Visit http://blogs.msdn.com/b/windowsazure/archive/2013/11/14/introduction-to-websockets-on-windows-azure-web-sites.aspx for more information on WebSocket support -->
<webSocket enabled="false" />
<handlers>
<!-- Indicates that the server.js file is a node.js site to be handled by the iisnode module -->
<add name="iisnode" path="app.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<!-- Do not interfere with requests for node-inspector debugging -->
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^app.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="public{REQUEST_URI}"/>
</rule>
<!-- All other URLs are mapped to the node.js site entry point -->
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="app.js"/>
</rule>
</rules>
</rewrite>
<!-- 'bin' directory has no special meaning in node.js and apps can be placed in it -->
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<!-- Make sure error responses are left untouched -->
<httpErrors existingResponse="PassThrough" />
<!--
You can control how Node is hosted within IIS using the following options:
* watchedFiles: semi-colon separated list of files that will be watched for changes to restart the server
* node_env: will be propagated to node as NODE_ENV environment variable
* debuggingEnabled - controls whether the built-in debugger is enabled
See https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config for a full list of options
-->
<iisnode watchedFiles="web.config;*.js"/>
</system.webServer>
</configuration>
If you throw the index.html into public folder which is created by yourself under wwwroot/ directly, you need to add the below code into your code based on this article.
app.use(express.static('public'))
I tested for that.
Update Answer:
I also turn on the Web Sockets Option.

How to host a service and static content in iisnode

I have my website working within express. But now I need to host it on IIS. How can I get my routing to work with IISNode?
I was able to move my static content to a /public folder (html, front end js, etc). I didn't want to do this, but got that part working.
I moved my server side logic to /server.
I had previously had .Net Web API style routing working, where my services were hosted at /api. I moved these to /server/api.
Whenever I try to request my API, I get a 404. How can I get this working with IISNode?
app.use("/api", require("./api"));
// routes/api/index.js
var router = require('express').Router();
router.use('/questionsets', require('./questionsets'));
module.exports = router;
var router = require('express').Router();
router.use('/questionsets', require('./questionsets.js'));
module.exports = router;
// routes/api/questions.js
var router = require('express').Router();
router.get('/', function (req, res) {
...
});
router.get('/:id', function (req, res) {
...
});
module.exports = router;
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin" />
</hiddenSegments>
</requestFiltering>
</security>
<handlers>
<add name="iisnode" path="bin/www" verb="*" modules="iisnode" />
</handlers>
<iisnode loggingEnabled="false" />
<httpErrors errorMode="Detailed" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" prefixLanguageFilePath="" path="/" responseMode="ExecuteURL" />
</httpErrors>
<rewrite>
<rules>
<rule name="LogFile" patternSyntax="ECMAScript" stopProcessing="true">
<match url="iisnode" />
</rule>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^bin\/www\/debug[\/]?" />
</rule>
<rule name="StaticContent" patternSyntax="ECMAScript" stopProcessing="true">
<match url=".*" />
<action type="Rewrite" url="{C:1}" logRewrittenUrl="true" />
<conditions>
<add input="{REQUEST_URI}" pattern=".*?\/(.*)" />
</conditions>
</rule>
<rule name="DynamicContent" patternSyntax="ECMAScript">
<match url=".*" />
<conditions>
<add input="{{REQUEST_FILENAME}}" matchType="IsFile" negate="True" />
</conditions>
<action type="Rewrite" url="server/app.js" logRewrittenUrl="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Source for url rewriting configuration
You need to install Application Request Routing here , and the documentation here.
Simply putting your server side files under /server would not work.
Start your express server, let's say listenning to http://localhost:3200/ ,
route request '/' to 'localhost:3200' will just route each request to your express server.

Resources