URL Rewrite not working - React SPA on Azure Web App (node) - node.js

I'm running a create-react-app build on an Azure Web App (node LTS). The app uses React Routes, and runs great from the index screen and as long as you are navigating the route links through the app. However, if you refresh a page, or navigate directly to a non-root route, you get 404. It seems to me like my web.config rewrite (of which I've tried many variations) is not being honored. I'm sure I'm just missing something obvious. Any suggestions?
index.js file
var express = require('express');
var server = express();
var options = {
index: 'index.html'
};
server.use('/', express.static('/home/site/wwwroot', options));
server.listen(process.env.PORT);
web.config (edit with updated version)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<webSocket enabled="false" />
<handlers>
<add name="iisnode" path="index.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="React Routes">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="True"/>
<add input="{REQUEST_URI}" pattern="/api" negate="true" />
</conditions>
<action type="Rewrite" url="/index.html" />
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
</configuration>
File Structure (/site/wwwroot/)
index.html
web.config
static/ (css, js)

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.

Deploy Angular Universal on IIS

I Have a Angular Universal Project and I need to run that on the IIS and must be run main.js in first time .
I Try for some Wat but it Not worked :
A : Install IISnode
B : Active CGI into the Turn windows features on or off
C : Using this web.config:
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="/main.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="/main.js" />
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<add segment="node_modules" />
<add segment="iisnode" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>
</configuration>
but its not worked for me , and Show me this Error :
How Can i Solve this Problem and run Angular universal in on IIS ?

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>

Http 404 on Azure Websites for react app

I have published a react app which works locally to an azure website, I checked the files on the KUDU dashboard, and I can see the files there and the index.html
However, I cant browse to the site, not even directly to the .html file.
I created this web.config, but I guess I am missing some configuration
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="server.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="^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="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="server.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>
Basically the answer is to change the web.config to handle routing correctly like this:
<?xml version="1.0"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="React Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

Azure node.js relative paths with graphql cli

I have a small node.js application acting as a graph-api created with graphql-cli.
Everything works fine on localhost, but when I try to run it in azure as a web app, I seem to have a problem with paths. The below snippet is working on localhost running npm start
const server = new GraphQLServer({
typeDefs: './src/schema.graphql',
resolvers,
context: req => ({
...req,
db: new Prisma({
typeDefs: 'src/generated/prisma.graphql',
endpoint: 'xxx',
secret: 'xxx',
debug: true,
}),
}),
})
The path to one of the .graphql-file is defined:
typeDefs: './src/schema.graphql',
Which I find a bit weird considering the folder structure where index.js is in the same folder as schema.graphql
Anyhow, this is working on localhost, but when trying to run it as an azure web app I get the following error:
No schema found for path: D:\home\site\wwwroot\src\src\schema.graphql
Since this is just a scaffolded app, I don't want to change the paths in code. I don't think they are wrong since it is working on localhost. I´m thinking that I'm missing some configuration on azure.
This is my web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<webSocket enabled="false" />
<handlers>
<add name="iisnode" path="src/index.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^src/index.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="src/index.js"/>
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
</configuration>
And my iisnode.yml looks just like this:
nodeProcessCommandLine: "D:\Program Files (x86)\nodejs\8.4.0\node.exe"
I´ve tried a bunch of different node versions, but I'm currently running 8.4.0 on my localhost where its working
Anyone has any ideas?
You need to move the index.js file to your root and change the web.config to:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<webSocket enabled="false" />
<handlers>
<add name="iisnode" path="index.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^index.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="index.js"/>
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
</configuration>

Resources