3

I've set up an angular4/node app on my local machine and I can ng serve and npm start the app just fine. I've created a web app on azure and used John Papa's guide to deploy it to azure. However; when I visit the site with chrome my index.html is not served up and I get a 404.
I've even eliminated all my documents under Application Settings -> Default Documents to only list index.html and nothing else.

However; when I visit myapp.azurewebsites.com/index.html the site is rendered. When I visit myapp.azurewebsites.com the site is not.

What am I missing?

server/index.js

const express = require('express');
const path = require('path');

const root = './dist';
const app = express();

app.use(express.static(root));
console.log(`server ${root}`);
app.get('*', (req, res) => {
    res.sendFile(`index.html`);
});

const port = process.env.PORT || '3000';
app.listen(port, () => console.log(`API running on localhost:${port}`));

client/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';

import { routes } from './app.routing';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        HttpModule,

        RouterModule.forRoot(routes)
    ],
    providers: [],
    bootstrap: [AppComponent]
    })
export class AppModule { }

client/app/app.routing.ts

import { Route } from '@angular/router';

import { AppComponent } from './app.component';

export const routes: Route[] = [
    { path: '', component: AppComponent }
];

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="index.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="^index.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="index.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>
gh0st
  • 1,653
  • 3
  • 27
  • 59

3 Answers3

11

MAY 2020 - You don't have to add any javascript files or config files anywhere. Let me explain.

I was facing this exact same issue and wasted 6 hours trying everything including the most popular answer to this question which didn't work either.

You see, when you just deploy an Azure Web App (or App Service as it is also called), two things happen:

  1. The web app by default points to opt/startup/hostingstart.html

  2. It also puts a hostingstart.html in home/site/wwwroot

When you deploy your code, it replaces hostingstart.html in home/site/wwwroot but the app is still pointing to opt/startup/hostingstart.html. If you want to verify this, try deleting opt/startup/hostingstart.html file and your web app will throw a "CANNOT GET/" error.

So how to change the default pointer? It's simpler than it looks:

Go to Configuration tab on your web app and add the following code to startup script:

pm2 serve /home/site/wwwroot --no-daemon

This will tell the web app to serve wwwroot folder. And that's it.

If this web app is a client-side single-page-app and you're having issues with routing, then add --spa to the above command as follows:

pm2 serve /home/site/wwwroot --no-daemon --spa 

Image for reference: Screenshot explaination

PS: If you only set the startup script without deploying your code, it will still show the hostingstart.html because by default that file lies in the wwwroot folder.

DeityWarrior
  • 716
  • 1
  • 6
  • 5
  • This is probably close to the right solution but all I get when I enter the start up script is "404 Not Found" when I try to view my node.js app – Matthew Oct 01 '21 at 09:24
5

If you deployed to a Node Linux Web App the default document would be hostingstart.html located in /home/site/wwwroot/

You could rename index.html to hostingstart.html.

According to the Azure App Service FAQ:

When you create a Node.js app, by default, it's going to use hostingstart.html as the default document unless you configure it to look for a different file. You can use a JavaScript file to configure your default document. Create a file called index.js in the root folder of your site and add the following content.

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);

This will configure index.html as the default document for your app.

Reference:

stormwild
  • 2,855
  • 2
  • 31
  • 38
0

It sounds like you are missing the web.config file from your root folder (the folder contain package.json). For reference, the below is a default web.config for an application that uses app.js as the entry point.

<?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 web app 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 web app entry point -->
        <rule name="DynamicContent">
          <conditions>
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True" />
          </conditions>
          <action type="Rewrite" url="app.js" />
        </rule>
      </rules>
    </rewrite>
    <!--
        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>

More on this:

Running Node.js on Azure Web App

Deploying Node JS application on Azure Web Services

Aaron Chen
  • 9,835
  • 1
  • 16
  • 28
  • So as part of my build on VSTS I have `-Handler iisnode -NodeStartFile index.js -appType node` on my Azure App Service Deploy tasks for the Web.config parameters. – gh0st Sep 08 '17 at 02:35
  • I'm unfamiliar with VSTS, can you please share the web.config with us? It is located in `D:\home\site\wwwroot` from Azure App Service and you can download it via Kudu Console (`https://.scm.azurewebsites.net/DebugConsole`). – Aaron Chen Sep 08 '17 at 08:30
  • web config is up, looks fine though – gh0st Sep 08 '17 at 14:21
  • actually, it seems like none of my routes being handled by my `app.routing.ts` are working; however, they work on my local machine – gh0st Sep 08 '17 at 22:36