Socket.io/Hapi Not Working Azure App Service (Linux) - node.js

I recently made a switch in our test environment from an Azure App Services Windows to Linux. Everything is working as it was previously except our socket connections. There seems to be a lot of outdated information regarding the Linux App Service, and the documentation is lackluster. However, according to these release notes, support is available for web sockets on Azure App Service Linux.
In some of Azure App Service for Linux documentation, it states that you must disable perMessageDeflate in order to get Web Sockets to work with Linux App Service and NodeJS. I believe I have done that in my HapiJS server code below. I have verified with a console.log(io) that the setting perMessageDeflate seems to be set to false correctly.
import Server from 'socket.io';
import socketioJwt from 'socketio-jwt';
const myHapiJSPlugin = {
name: 'myPluginName',
version: '2.0.0',
register: function (server, options) {
const io = new Server(server.listener, {
perMessageDeflate: false,
transports: ['websocket'],
origins: '*:*'
});
io.use(socketioJwt.authorize({
secret: JWT_SECRET_KEY,
handshake: true
}));
io.on('connection', socket => {
console.log(io);
// more code here
};
};
};
When I open the network page of Chrome's console while using my web client, I get a 101 response code from the server. I console.log connects/disconnects from the socket.io's client's callbacks. I can see it continually connects/disconnects despite getting an acknowledgement from the server (101 response). The state of the connections says 'stalled' in the console. I seem to be subscribing to a particular route okay as the callback fires.
I have made no other code changes since switching from Azure App Services Windows despite the configuration below to add perMessageDeflate and origins for testing socket.io docs. I'm thinking something is going wrong during the handshake or authentication.
Status Code: 101 Switching Protocols
Access-Control-Allow-Origin: *
Connection: Upgrade
Date: Tue, 01 Oct 2019 18:04:57 GMT
Sec-WebSocket-Accept: <HASH>
Server: Kestrel
Upgrade: websocket
I also added perMessageDeflate to my client side code. It didn't make a difference.
const client = new io(URL, {
query: 'token=' + jwt,
perMessageDeflate: false,
transports: ['websocket'],
upgrade: false
});
What else am I missing? How do I enable web sockets on Azure App Service Linux? I checked for a configuration setting like with Windows. There does not appear to be a setting for that - as it seems web sockets are enabled by default. I have verified in the logs that the web server is not continually restarting causing the connect/disconnects.

Do your WebSockets work if the Authentication is turned off?
I only experience problems with WebSockets using Linux Apps when I enable the Authentication features.
I believe this is due to a poor implementation of the EasyAuth proxy, and that it is considered a difficult problem for MS to fix.

tl;dr
Disable CORS and AUTH through the portal on Linux App Service.
Disable CORS by going to your App Service, select CORS on the left side menu bar under API, remove any entries in there. By removing all entries, you are disabling Azure's CORS implementation for App Service.
Disable AUTH by going to Authentication/Authorization under the Settings heading on the left side menu bar. Click the switch to 'off'.
This will allow Web Sockets to work as expected with Linux App Service. However, you need to configure CORS and AUTH with your web server framework now.
Long Form
After hearing back from my MS support rep, she confirmed that when CORS or AUTH is enabled it breaks Linux App Service's sockets implementations. The Linux App Service CORS and AUTH features are not implemented yet by Microsoft.
In order to use Linux App Service and utilize the CORS or AUTH features, you simply can't because it's not implemented. The official recommended solution is to switch to Windows App Service.
Despite what the Azure documentation states, perMessageDeflate is not required for WebSockets to work with socket.io. I have it working without it correctly. To configure CORS for the App Service from the portal, it's the same as you would for Windows. You can go to your App Service in the portal, select CORS on the left side menu under API. Delete any entries in there to disable App Service's CORS feature. I had only one entry (*) that I was using during testing since I had CORS configured correctly with my Windows App Service before switching to Linux.
If you remove all entries, you should have functioning Web Sockets without CORS. However, keep in mind, you should configure CORS with your web server framework for security reasons. If it's express with socket.io, you'll have to do something like this. Most web frameworks follow a similar paradigm by specifying it on your server object as an option.
There some more information regarding this in this thread on GitHub.

I had similar issues on Node. socket.io was failing on App services run on Linux on an azure cdn hosted domain.
Was able to mitigate this by using the Custom Domain and TLS/SSL settings to link my domain to the app service url instead of setting up an azure cdn on the app service.

Related

Blazor websocket disconnects when using Application Gateway

I have two blazor server (.NET 6) apps running as app services in Azure. The apps are to be "hidden" behind an application gateway to give users the impression that they are visiting the same site. Traffic is to be directed using parts of the url i.e {{domain}}/* go to app 1, {{domain}}/{{keyword}} go to app 2.
This has been set up, using routing rules on the gateway and the routing works as expected, with requests reaching the correct apps. However, when reaching app 2, the websocket immediately disconnects, killing blazor in the process. Error message displayed in the console of app 2. The apps are very barebones, containing very little code as this is a POC.
Things I have tried:
Use Azure SignalR and not using it.
Configured both apps to use websocket
Use different routing rules for the two apps and use the same routing rule with two backend pools.
Use Azure Front Door, but the same issue persists.
Randomly toggle settings
Added options.ServerStickyMode = ServerStickyMode.Required; to the signalR config in program.cs
Added `#inject Microsoft.AspNetCore.Http.IHttpContextAccessor _HttpContext
#{
_HttpContext.HttpContext.Response.Headers["Cache-Control"] = "no-store";
}` to _Layout.cshtml with the _HttpContext. yadayada both inside the body and outside.
Maybe the most frustrating thing is that it works just fine when reaching the first app. I have tried switching the deploys, i.e. deploy app 1 code to app 2 service and vice versa, to no avail.
Have anyone else experience a similar thing? Any config or code changes I have missed?

React application deployed on azure is not using Http2 even though Http2.0 is enabled for app service on azure

I have deployed my react application on Azure App Service with .NET Stack (.NET Core 3.1,2.1). I have enabled Http2.0 from Azure App Service > Configuration > General Settings and also from azure resource explorer. At both places it shows Http2.0 but browser still uses Http1.1. TLS Settings are Https only and TLS version 1.2
There is no problem with this function.
I reproduced your problem. You only need to open a new privacy mode window and refresh it a few times to see the new settings take effect.
This problem may be caused by browser cache, etc.
Test Result.
In front of the APP service WAF was enabled. And WAF was not supporting Http2.0

SignalR core: is ARR affinity needed when web sockets are enabled and the Azure app service is scaled out to multiple instances?

I'm working on an asp.net core 2.2 MVC web application. We are using signal r core version 1.1.0 (added via the nuget package Microsoft.AspNetCore.SignalR). The client side application is an angularjs application referencing version 1.1.4 of the aspnet-signalr javascript library.
Our application is deployed on Azure and the hosting app service is scaled horizontally : there currently two instances of our web application up and running. I'm testing the behavior of my application by using Google chrome version 75.0.3770.100 on a windows 10 machine.
The app service is configured so that the web sockets are enabled and the ARR affinity is disabled. I'm experiencing a strange behavior, basically if I test my application and I perform several browser hard refresh (ctrl + F5) it happens randomly that the client side application is unable to connect to the notification hub. The following errors are reported in the google chrome console:
WebSocket connection to 'wss://myapp.azurewebsites.net/notificationsHub?id=3Fmlw2yC5qm3vi0qny50Qg' failed: Error during WebSocket handshake: Unexpected response code: 404
Error: Failed to start the transport 'WebSockets': null
GET https://myapp.azurewebsites.net/notificationsHub?id=nEYPEDw5f0AkLz5otCAOyA 404
Error: Failed to start the transport 'ServerSentEvents': Error: Error occurred
GET https://myapp.azurewebsites.net/notificationsHub?id=2G9VVr5mcx7QT2wbSfwDLA&_=1561652513485 404
Error: Failed to start the transport 'LongPolling': Error
Error: Failed to start the connection: Error: Unable to initialize any of the available transports.
If I change the app service configuration so that both the web sockets and the ARR affinity are enabled everything works like a charm. My suspicious is that when the app service is horizontally scaled then the ARR affinity is required regardless of the transport protocol (in my case, both the server side application and the client browser are able to support the web socket protocol).
Based on my understanding, the official microsoft documentation states that when using web sockets as a communication protocol the client ARR affinity is not required, even if the hosting app service is horizontally scaled to multiple instances. At this point I'm not sure about my understanding of the signalr core documentation.
Am i missing something ? Did I misunderstood the official documentation ?
EDIT 3 JULY 2019
For the ones interested to this subject (scaling out a web application using signal-r core), you can refer to this github issue for all the details.
The short answer is that the new signal-r core is actually stateful and requires sticky sessions when the application is scaled out to multiple servers.
If you are on Azure only, you can avoid the usage of sticky sessions and have several other benefits by using the Azure signalr service.
If you don't want to use this azure service the only option to avoid sticky sessions is configuring signal r core so that the client-server protocol negotiation is avoided and the communication is done by using web sockets only (refer to the linked github issue for all the details). Notice that doing so you will lose the ability of downgrading to other protocols when web sockets aren't supported, which is one of the core features of signal-r core.
If you want to affinity disable, then I think the component you're missing is the hosted SignalR service. It's the proxy service that will maintain session info for you as your app service scales out. Follow these steps to add SignalR service as a service dependency to your project.

Signalr Issue on Azure Service Fabric: Error during WebSocket handshake

We are using Service Fabric for hosting our messaging service ASP.NET Core web API (leveraging signalr) and React web application as a client. Everything works exactly as expected on local machines but not on Azure. We have configured CORS policies for cross-origin handling since the service and the web app are hosted on different servers. Configured sticky sessions in load balancer. This CORS Policy works in local machine with the service and client hosted on different ports.
Post hosting the application on Azure, I get an Error in the browser console as
Error during WebSocket handshake: Unexpected response code: 500
The issue is very likely to be happening because of CORS.
Looking the screenshot you provided, it is possible to see the CORS exception and, as you are aware, the front-end application calling the SignalR service are hosted on different locations(The domain is the same but different ports).
The CORS settings you applied probably didn't work.
You have two solutions:
Configure CORS in the ASP.NET CORE, so SignalR can accept the call from other domains.
Host both on same domain + port to avoid CORS

IBM API Connect apps published to Bluemix inaccessible

I followed API Connect getting started guide to create a local loopback API app and tested successfully. Then I am trying to follow Publish Your API to Bluemix. The publishing is successful. The app is running. But clicking the app yields Chrome error:
This site can’t provide a secure connection
ddd.abbr-dev2.apic.mybluemix.net sent an invalid response.
I suspect the problem is incorrect port. According to CloudFoundry Nodejs tips, the port should use process.env.PORT, but loopback defaults to 3000. Following this clue, I tried adding config.local.js:
module.exports = {
port: process.env.PORT
};
But the service end point is still inaccessible.
Please Help. Thanks
This is actually by design. Since your API's implementation is on the public internet, it is secured via Mutual TLS. The only way to access it is via the API Connect gateway, thus ensuring the API is managed.
If you want to make it accessible publicly, open the app in the Bluemix console and add an additional route to the app, using the mybluemix.net domain.

Resources