Express NodeJS web.config in Azure for SVG & Fonts - node.js

I had a problem in an Express website, which uses SVG and other files like fonts.
Did not have any problem when running app locally, but once deployed on Azure, SVG and fonts didn't appear anymore.
Created a web.config file at project root:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<staticContent>
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
<mimeMap fileExtension=".woff" mimeType="application/x-woff" />
<mimeMap fileExtension=".ttf" mimeType="application/x-woff" />
</staticContent>
</system.webServer>
</configuration>
Also used this solution: (Svgs and other mime types in windows azure)
Both solutions now permit to load SVG files, but webpages are not loaded anymore. (HTTP 500)
It seems it overrides configuration for Dynamic Content.
How should Dynamic Content be configured to make app work again?

I found the problem.
Used this solution: (Svgs and other mime types in windows azure)
And in Dynamic Content Rewrite Rule, replaced server.js by app.js, which is the default entry point created by Express.
Final result is:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<staticContent>
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
<mimeMap fileExtension=".woff" mimeType="application/x-woff" />
<mimeMap fileExtension=".ttf" mimeType="application/x-woff" />
</staticContent>
<handlers>
<add name="iisnode" path="app.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<rule name="DynamicContent">
<match url="/*" />
<action type="Rewrite" url="app.js" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

Related

Deploy angular universal on IIS 10

I am trying to deploy angular universal on IIS 10, I followed this article https://www.thecodehubs.com/how-to-deploy-ssr-angular-universal-to-iis/
This is my Web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="main.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<rule name="DynamicContent">
<match url="/*" />
<action type="Rewrite" url="main.js"/>
</rule>
<rule name="StaticContent" stopProcessing="true">
<match url="([\S]+[.](jpg|jpeg|gif|css|png|js|ts|cscc|less|ico|html|map|svg))" />
<action type="None" />
</rule>
</rules>
</rewrite>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" />
<remove fileExtension=".svg" />
<remove fileExtension=".eot" />
<remove fileExtension=".ttf" />
<remove fileExtension=".woff" />
<remove fileExtension=".woff2" />
<remove fileExtension=".otf" />
<mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
<mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
<mimeMap fileExtension=".woff" mimeType="application/x-woff" />
<mimeMap fileExtension=".woff2" mimeType="application/x-woff" />
<mimeMap fileExtension=".otf" mimeType="application/otf" />
</staticContent>
</system.webServer>
</configuration>
This is my app folder on IIS
But when i start my website on IIS, I got this error
The iisnode module is unable to start the node.exe process. Make sure the node.exe executable is available at the location specified in the system.webServer/iisnode/#nodeProcessCommandLine element of web.config. By default node.exe is expected in one of the directories listed in the PATH environment variable.
So I added this line to my web.config file just before </system.webServer>
<iisnode nodeProcessCommandLine="C:\Program Files\nodejs\node.exe" />
</system.webServer>
</configuration>
But the same problem still exists. this is my ProgramFiles, here i noticed that the nodejs has shortcut , I am using nvm (node version manager). Is this the reason ?
Yes you are right, this is because you are using nvm, i faced this issue before.
Switch off node version manager by running in cmd
nvm off
Install node js on your machine, then it will run without any issue.

Why node.js does not load website after a server restart?

I use Windows Server Standard 2019 to host an Angular 11 Universal with ASP.net Core 3.1.1 website. The website was working great until a server restart. I did many tests to make sure there is no memory leak or some error from the angular app and everything is absolutely perfect. Then I had to restart the server to install some windows updates and then the website was not working anymore. It does an infinite loading.
The thing is if I kill the Node.js JavasScript Runtime running in Background processes which run after the server has restarted and immediately refresh the website, Node will launch a new process and the website will works as expected until the next server restart. I made many other tests to found that specific case scenario.
So, I am not sure how to solve this. Naturally, I want the website to work immediately after a server restart without any intervention from my side. Here are the files and configurations I guess should help to aim the problem, let me know if you need other info:
Website the folder structure:
dist (folder)
iisnode (folder)
main.js
node_start.cmd
Web.config
I installed nodejs 14.16.0 LTS first then 15.11.0 Current and also Url Rewrite 2.1 and iisnode-full-v0.2.21-x64
The IIS is version 10. I tried setting the Application Pools to:
Start application pool immediately
Start mode: AlwaysRunning
Idle Time-out Action: Suspend
Maximum Worker Processus: 0
Preload Enabled: True
I repeat the website works as expected when I kill the Node.js JavasScript Runtime in the background which run after the server has restarted and then hit refresh to reach the website. Finally, the website works with a valid SSL certificate.
Here the content of node_start.cmd
cd "C:\inetpub\wwwroot\championstogether" "C:\Program
Files\nodejs\node.exe" "C:\inetpub\wwwroot\championstogether\main.js"
Then the Web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="StaticFilesCss" path="*.css" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
<add name="StaticFilesPng" path="*.png" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
<add name="iisnode" path="main.js" verb="*" modules="iisnode" responseBufferLimit="0" />
</handlers>
<iisnode nodeProcessCommandLine="C:\Program Files\nodejs\node.exe --no-deprecation --no-warnings"
flushResponse="false"
promoteServerVars="HTTP_UID,HTTP_PUBCOOKIE_USER,LOGON_USER,HTTP_SHIBSESSIONID"
node_env="production"
nodeProcessCountPerApplication="0"
debugHeaderEnabled="false"
devErrorsEnabled="false"
gracefulShutdownTimeout="60000"
maxConcurrentRequestsPerProcess="1024"
maxNamedPipeConnectionRetry="100"
namedPipeConnectionRetryDelay="250"
maxNamedPipeConnectionPoolSize="512"
maxNamedPipePooledConnectionAge="30000"
asyncCompletionThreadCount="0"
initialRequestBufferSize="4096"
maxRequestBufferSize="65536"
uncFileChangesPollingInterval="5000"
loggingEnabled="true"
logDirectory="iisnode"
debuggingEnabled="true"
debuggerPortRange="5058-6058"
debuggerPathSegment="debug"
maxLogFileSizeInKB="128"
maxTotalLogFileSizeInKB="1024"
maxLogFiles="20"
enableXFF="false"
configOverrides="iisnode.yml"
watchedFiles="web.config;*.js;routes\*.js;views\*.pug"/>
<rewrite>
<rules>
<rule name="DynamicContent">
<match url="/*" />
<action type="Rewrite" url="main.js" />
</rule>
<rule name="StaticContent" stopProcessing="true">
<match url="([\S]+[.](jpg|jpeg|gif|css|png|js|ts|cscc|less|ico|html|map|svg))" />
<action type="None" />
</rule>
<rule name="SocketIO" patternSyntax="ECMAScript">
<match url="socket.io.+"/>
<action type="Rewrite" url="main.js"/>
</rule>
<!-- Don't interfere with requests for node-inspector debugging -->
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^main.js\/debug[\/]?"/>
</rule>
</rules>
</rewrite>
<!-- Make sure error responses are left untouched -->
<httpErrors existingResponse="PassThrough" />
<modules runAllManagedModulesForAllRequests="false" />
<staticContent>
<clientCache cacheControlMode="UseMaxAge" />
<remove fileExtension=".svg" />
<remove fileExtension=".eot" />
<remove fileExtension=".ttf" />
<remove fileExtension=".woff" />
<remove fileExtension=".woff2" />
<remove fileExtension=".otf" />
<mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
<mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
<mimeMap fileExtension=".woff" mimeType="application/x-woff" />
<mimeMap fileExtension=".woff2" mimeType="application/x-woff" />
<mimeMap fileExtension=".otf" mimeType="application/otf" />
</staticContent>
</system.webServer>
</location>
</configuration>
Thank you for any help,
Samantha
Samantha -
Based on your web.config file, I see you are using the iisnode module. The iisnode module actually has a bug that requires a manual restart of the Node.js process after a server restart, and to my knowledge, a fix has never been conclusively developed.
Although Microsoft is now in possession of the code, they did not create it, nor are they actively maintaining it. Quite frankly, I am surprised they have not already released an official notice about deprecation.
The alternative options for running node.js apps on IIS are either to use the ARR (reverse proxy) module or the HttpPlatformHandler module. ARR is extremely generic; it does not support Node.js specific variables or even a specification that Node is being used in the web.config.
My suggestion would be to use the HttpPlatformHandler module, which can manage any process, including Node, and also any proxy requests to and from the parent process. While still basically a reverse proxy, this module can be configured for a node.js process. The web.config should look something like this.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpPlatformHandler" path="main.js" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers>
<httpPlatform processPath="C:\Program Files\nodejs\node.exe"
arguments=""
startupTimeLimit=20
startupRetryCount=10
rapidFailsPerMinute=10
requestTimeout="00:02:00"
stdoutLogEnabled=true
stdoutLogFile="httpplatform-stdout"
processesPerApplication=0
forwardWindowsAuthToken=false>
<environmentVariables>
<environmentVariable name="PORT" value="%HTTP_PLATFORM_PORT%" />
<environmentVariable name="NODE_ENV" value="Production" />
</environmentVariables>
</httpPlatform>
// add the config details for the rest of your module here
</system.webServer>
</configuration>
ADDITIONAL REFERENCES --
Official
Microsoft Documentation
Download & Support Page
Community
Node & IIS Configuration Discussion Thread
Peter Eyserman's Blog Article
Based on #killshot13 answer, I got nodejs to work with HttpPlatformHandler. The website takes maybe 3 minutes to load the first time after a server restart. I'm little disapointed about not being able to configure nodejs with nodeProcessCountPerApplication="0" or flushResponse="false" but perhaps someone else know how.
So here the answer :
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="httpplatformhandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" requireAccess="Script" />
</handlers>
<httpPlatform
arguments=".\main.js"
stdoutLogEnabled="true"
stdoutLogFile=".\node.log"
startupTimeLimit="20"
startupRetryCount="10"
rapidFailsPerMinute="10"
requestTimeout="00:02:00"
processesPerApplication="2"
processPath="C:\Program Files\nodejs\node.exe --no-deprecation --no-warnings">
<environmentVariables>
<environmentVariable name="PORT" value="%HTTP_PLATFORM_PORT%" />
<environmentVariable name="NODE_ENV" value="production" />
</environmentVariables>
</httpPlatform>
<!-- Make sure error responses are left untouched -->
<httpErrors existingResponse="PassThrough" />
<modules runAllManagedModulesForAllRequests="false" />
<staticContent>
<clientCache cacheControlMode="UseMaxAge" />
<remove fileExtension=".svg" />
<remove fileExtension=".eot" />
<remove fileExtension=".ttf" />
<remove fileExtension=".woff" />
<remove fileExtension=".woff2" />
<remove fileExtension=".otf" />
<mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
<mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
<mimeMap fileExtension=".woff" mimeType="application/x-woff" />
<mimeMap fileExtension=".woff2" mimeType="application/x-woff" />
<mimeMap fileExtension=".otf" mimeType="application/otf" />
</staticContent>
</system.webServer>
</location>
<system.webServer>
<defaultDocument>
<files>
<clear />
<add value="index.html" />
<add value="index.htm" />
<add value="iisstart.htm" />
<add value="default.aspx" />
</files>
</defaultDocument>
</system.webServer>
</configuration>

Blazor WASM - Standalone Deployment on IIS

I'm trying to get a Blazor WASM app deployed on IIS, following the instructions here.
This is just the out of the box sample Blazor WASM app
I've published the app to a folder
I've added the URL rewriting module to IIS
I've added dynamic compression support to IIS
I created a new web app in the default website and pointed it to the folder where I published the Blazor app
Invoking the app produces a page containing "An unhandled error has occurred. Reload".
Looking at the requests in the browser dev tools, index.html is being fecthed from the wwwroot folder, suggesting that the url rewrite rule is firing, but the requests for css/bootstrap.min.css, _framework/blazor.webassembly.js and css/app.css all fail with status 404 - Not Found.
What am I missing?
Windows 10 2004.
try to set the base path in your index.html file:
<base href="/CoolApp/">
below is the iis application folder path:
you can set it to your publish folder.
web.conifg file:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<remove fileExtension=".dat" />
<remove fileExtension=".dll" />
<remove fileExtension=".json" />
<remove fileExtension=".wasm" />
<remove fileExtension=".woff" />
<remove fileExtension=".woff2" />
<mimeMap fileExtension=".dll" mimeType="application/octet-stream" />
<mimeMap fileExtension=".dat" mimeType="application/octet-stream" />
<mimeMap fileExtension=".json" mimeType="application/json" />
<mimeMap fileExtension=".wasm" mimeType="application/wasm" />
<mimeMap fileExtension=".woff" mimeType="application/font-woff" />
<mimeMap fileExtension=".woff2" mimeType="application/font-woff" />
</staticContent>
<httpCompression>
<dynamicTypes>
<add mimeType="application/octet-stream" enabled="true" />
<add mimeType="application/wasm" enabled="true" />
</dynamicTypes>
</httpCompression>
<rewrite>
<rules>
<rule name="Serve subdir">
<match url=".*" />
<action type="Rewrite" url="wwwroot\{R:0}" />
</rule>
<rule name="SPA fallback routing" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="wwwroot\" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
index file:
output:
Note: make sure you assign the iis_iusrs and iusr permission to the site folder.
https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/?view=aspnetcore-3.1&tabs=visual-studio

How to fix "Failed to load resource 404" after deploying angular application to azure portal web app

I am trying to deploy an angular application to Microsoft azure app service via the dist folder. I run the script "ng build --prod" to generate a dist folder, compressed it, and uploaded it to the deploy site for azure service. Then only a part of the website is loaded and there are a lot of 404 errors. Here is my temporary web link: https://tes42.azurewebsites.net
The angular application has a rooter called "books", and the index.html file in the dist folder has code. I am thinking if the problem is caused by this?
To fix these 404 errors, you'll need to add a web.config file to your root with the following content:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="AngularJS" stopProcessing="true">
<match url="^(?!.*(.bundle.js|.bundle.map|.bundle.js.gz|.bundle.css|.bundle.css.gz|.png|.jpg|.ico|.svg|.eot|.woff|\​.woff2)).*$" />
<conditions logicalGrouping="MatchAll"></conditions>
<action type="Rewrite" url="/" appendQueryString="true" />
</rule>
</rules>
</rewrite>
<staticContent>
<remove fileExtension=".svg" />
<remove fileExtension=".eot" />
<remove fileExtension=".woff" />
<remove fileExtension=".woff2" />
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
<mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
<mimeMap fileExtension=".woff" mimeType="application/font-woff" />
<mimeMap fileExtension=".woff2" mimeType="application/font-woff" />
</staticContent>
</system.webServer>
</configuration>

Send a Response.Status = "404 Not Found" but let IIS remain on the same page

I have a simple question:
Is possible to send the Response.Status = "404 Not Found" from a .asp page, but continue to render the actual page?
Seems that when i send Response.Status = "404 Not Found" IIS moves to the default 404 error page, while i would like to continue to render my page. This is a case of a CMS where for some reason someone can type a unexistent permalink and want to display a "OPS not found content page" instead to redirect to a custom or default 404 asp page.
there is a specific web.config setup?
I've followed discussion here:
Configuring custom ASP 404 page with redirect for IIS7 website
And thought to use then option
<httpErrors existingResponse="PassThrough" />
But for some reason it gave me error 500.
The IIS version is 8.5 asp 3.0 / .NET 3.5
my actual web.config is:
<?xml version="1.0" encoding="UTF-8"?>
<httpErrors errorMode="DetailedLocalOnly"/>
<urlCompression doDynamicCompression="true" doStaticCompression="true" dynamicCompressionBeforeCache="true" />
<caching enabled="true">
<profiles>
<add extension=".gif" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange" duration="0.00:01:00" location="Any" />
<add extension=".png" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange" duration="0.00:01:00" location="Any" />
<add extension=".js" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange" duration="0.00:01:00" location="Any" />
<add extension=".css" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange" duration="0.00:01:00" location="Any" />
<add extension=".jpg" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange" duration="0.00:01:00" location="Any" />
<add extension=".jpeg" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange" duration="0.00:01:00" location="Any" />
</profiles>
</caching>
<staticContent>
<remove fileExtension=".js" />
<mimeMap fileExtension=".js" mimeType="text/javascript" />
<remove fileExtension=".eot" />
<remove fileExtension=".ttf" />
<remove fileExtension=".otf"/>
<remove fileExtension=".woff"/>
<remove fileExtension=".woff2"/>
<mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
<mimeMap fileExtension=".ttf" mimeType="font/ttf" />
<mimeMap fileExtension=".otf" mimeType="font/otf" />
<mimeMap fileExtension=".woff" mimeType="font/x-woff" />
<mimeMap fileExtension=".woff2" mimeType="font/x-woff2" />
<clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="30.00:00:00" />
</staticContent>
<rewrite>
<rules>
<rule name="Rewrite to friendly URL">
<match url="^site/([_0-9a-z-]+)" />
<action type="Rewrite" url="/default.asp?pl={R:1}" />
</rule>
</rules>
</rewrite>
Thank in advance for any solution :)
EDIT:
After many test i found the solution:
<httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough"/>
The 500 error i get if i add the line separate from the "DetailedLocalOnly" is now solved using a one line with both param.
Maybe it is only a typo in your web.config. If above is your configuration file, you forgot to enter the system.webServer tag level.
I tested this on IIS 8.5 and it worked as expected. So the ASP generated
content was shown while the page returned a 404 status code. I really only used following configuration:
<configuration>
<system.webServer>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
</configuration>
Alternatively, but not recommended, it also worked with following configuration:
<configuration>
<system.web>
<customErrors mode="Off" />
</system.web>
<system.webServer>
<httpErrors errorMode="Detailed" />
</system.webServer>
</configuration>
For the interested, here is the link to the documentation.

Resources