SignalR can't connect when deployed behind AWS EB - amazon-web-services

I am trying to use SignalR on an application hosted in AWS EB, with an application loadbalancer in front.
It works perfectly fine when I test it locally, but when deployed, the websocket can not establish a connection and returns:
"Error: Failed to start the connection: Error: There was an error with the transport."
And
"There was an error with the transport. at WebSocket.o.onerror [as __zone_symbol__ON_PROPERTYerror]"
I have tried adding a middleware at the very start of my pipeline, that logs if i get a request for my hub, and this works, so I dont think it is the load balancer or anything AWS Related.
If i call the URL with Postman websocket, I get a status code 400.
I have followed the MS guide and added the configuration for JWT auth
jwtTokenOptions.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// If the request is for our hub...
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
(path.StartsWithSegments("/signalr")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
And as I said, it works fine locally. Any suggestions are most welcome

I fixed this by enabling web sockets for the IIS on the eb instance.
I did this by creating an eb extension with the following command
commands:
01_install_websockets_feature:
command: "%SystemRoot%\\System32\\dism.exe /online /enable-feature /featurename:IIS-WebSockets"
ignoreErrors: true

Related

"Invalid protocol" when trying to connect to Elasticache Redis in Node.js

I'm trying to connect an ElastiCache Redis to an Express server deployed on ECS. I'm using the Official Redis package for Node.js
I get the Primary Endpoint from ElastiCache as blablabla.mccjet.ng.0001.euc1.cache.amazonaws.com:6379
In my server I try to connect like this
const { createClient } = require("redis");
const pubClient = createClient({ url: 'blablabla.mccjet.ng.0001.euc1.cache.amazonaws.com:6379' });
But when I check the ECS logs I see
/usr/src/app/node_modules/#redis/client/dist/lib/client/index.js:124
throw new TypeError('Invalid protocol');
^
TypeError: Invalid protocol
at Function.parseURL (/usr/src/app/node_modules/#redis/client/dist/lib/c...
Haven't used Redis so no idea why this is happening. Any idea how to use the endpoint properly
even tried with
const pubClient = createClient({ host: 'blablabla.mccjet.ng.0001.euc1.cache.amazonaws.com', port:6379 });
but that also didn't work
The issue was I had to add the prefix redis:// before my Primary endpoint so that it becomes redis://blablabla.mccjet.ng.0001.euc1.cache.amazonaws.com:6379
Github Issue
const pubClient = createClient({ url: 'redis://blablabla.mccjet.ng.0001.euc1.cache.amazonaws.com:6379' });

SignalR returns "Connection ID required" when ran in an AWS ECS container

I am trying to get a .Net Core 3.1 SignalR Web API with an Angular front end to work with websockets.
The code works perfectly fine when ran locally, either from within in the IDE or via docker run. However, once the code gets deployed to an ECS instance in AWS behind an API Gateway the web sockets refuse to connect.
I setup my mappings like so:
app.UsePathBase("/ui");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
"default",
"{controller}/{action=Index}/{id?}")
.RequireCors(PolicyName);
endpoints.MapHub<SessionHub>("/ws/session");
endpoints.MapHub<SessionsHub>("/ws/sessions");
});
And on the client I connect to the hub like so:
this.sessionsHubConnection = new HubConnectionBuilder()
.withUrl(`${window.origin}/ws/sessions`, {
skipNegotiation: true,
transport: HttpTransportType.WebSockets,
accessTokenFactory: () => this.getAccessToken()
})
.withAutomaticReconnect()
.build();
The following Fiddler trace shows the initial HTTP request to initialize the websocket connection and the error being returned by kestrel.
I tweaked my web socket middleware for handling the access token to also Console.Write some additional debugging statements that I think might prove insightful:
public async Task Invoke(HttpContext httpContext)
{
var request = httpContext.Request;
Console.WriteLine($"Starting connection id: {httpContext.Connection.Id}");
// web sockets cannot pass headers so we must take the access token from query param and
// add it to the header before authentication middleware runs
if (request.Path.StartsWithSegments("/ws", StringComparison.OrdinalIgnoreCase)
&&
request.Query.TryGetValue("access_token", out var accessToken))
{
request.Headers.Add("Authorization", $"Bearer {accessToken}");
}
try
{
var sb = new StringBuilder();
sb.AppendLine($"Connection Id: {httpContext.Connection.Id}");
Console.WriteLine(sb.ToString());
await _next(httpContext);
sb = new StringBuilder();
sb.AppendLine($"Status code {httpContext.Response.StatusCode}"); <-- this line
sb.AppendLine($"Connection Id: {httpContext.Connection.Id}"); <-- and this line
Console.WriteLine(sb.ToString());
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
throw;
}
}
And in the AWS logs you can see that the connection Id is present but is being ignored by the EndpointMiddleware(?) for some reason.
Any idea what could be causing this? Two ideas I have yet to be able to rule out are:
The HTTP/S termination at our API gateway is confusing Kestrel since the browser client is building the socket request under HTTPS, but as far as Kestrel is concerned everything is communicating over HTTP?
app.UsePathBase("/ui"); is confusing Kestrel and all the web socket paths should actually be /ui/ws/session?

Why website is not auditable or readable for google?

Have created a staging website on Herokuapp and production on AWS but whenever trying to audit or speed testing it's giving an attached error
http://findmy-web.herokuapp.com/ staging -> hosted on heroku
https://www.gocatchy.com/ live -> hosted on AWS
Technology used = node and react
folks issue is resolved.
As I checked server-side config there was context URL response with status code 400
res.status(400).send(fullMarkup);
have updated with 200 and its works!

How to connect to ElasticSearch on AWS via reactivesearch-proxy-server

I'm setting up my first ElasticSearch app using ReactiveSearch to connect to an ElasticSearch index I created on AWS.
I'm new to Node.js and most of the technology involved here. I think I have a basic ReactiveSearch app that works but it won't connect to my AWS ElasticSearch index. When I enter a search I get no output and no errors.
I followed the ReactiveSearch Quickstart guide:
https://opensource.appbase.io/reactive-manual/getting-started/reactivesearch.html
I created the Boilerplate App with CRA:
https://github.com/facebook/create-react-app#creating-an-app
The app runs ok but there is no output when I try to search.
Then I saw the note that you have to use a proxy with AWS. I cloned https://github.com/appbaseio-apps/reactivesearch-proxy-server and got that working and I now have a proxy that runs on http://localhost:7777/
My Search App connects to the proxy like this:
<ReactiveBase
app="my-search"
url="http://localhost:7777">
This is the code that sets the target in the proxy. I commented out the authorisation because I'm not using appbase.io.
const options = {
target: 'https://search....ap-southeast-2.es.amazonaws.com',
changeOrigin: true,
onProxyReq: (proxyReq, req) => {
/* proxyReq.setHeader(
'Authorization',
`Basic ${btoa('cf7QByt5e:d2d60548-82a9-43cc-8b40-93cbbe75c34c')}`
);*/
/* transform the req body back from text */
const { body } = req;
if (body) {
if (typeof body === 'object') {
proxyReq.write(JSON.stringify(body));
} else {
proxyReq.write(body);
}
}
}
}
I can see the ReactiveSearch app on my browser at http://localhost:3000
When I type keywords into the search box I see output like this in the proxy app:
Verifying requests ✔ {"preference":"results"}
{"query":{"bool":{"must":[{"bool":{"must":[{"bool":{"should":[{"multi_match":{"query":"cables","fields":["Description"],"type":"best_fields","operator":"or","fuzziness":0}},{"multi_match":{"query":"cables","fields":["Description"],"type":"phrase_prefix","operator":"or"}}],"minimum_should_match":"1"}}]}}]}},"size":50,"_source":{"includes":["*"],"excludes":[]},"from":0}
Verifying requests ✔ {"preference":"SearchBox"}
{"query":{"bool":{"must":[{"bool":{"must":{"bool":{"should":[{"multi_match":{"query":"horse","fields":["Description"],"type":"best_fields","operator":"or","fuzziness":0}},{"multi_match":{"query":"horse","fields":["Description"],"type":"phrase_prefix","operator":"or"}}],"minimum_should_match":"1"}}}}]}},"size":20}
What am I missing to get the connection working? Do I need to add some kind of authentication in AWS and add passwords to the proxy code?
Is there a way to see some debugging info?
Thanks,
Phil

Websocket connection to Rabbitmq over SSL through ELB

I have installed a rabbitmq server on my AWS instance that is behind a load balancer. I am currently able to connect, send and receive messages using js from an http url. However when I attempt the same feat from an https url I cannot successfully maintain a connection.
The following snippet shows the several tacks I have taken so far:
var ws = null;
if (window.location.protocol.indexOf("https") >= 0){
//1 ws = new WebSocket('wss://myelbpublicdns.com:15674/ws');
//2 ws = new WebSocket('wss://myec2publicdns.com:15674/ws');
//3 ws = new WebSocket('wss://myurl.com:15674/ws');
} else {
ws = new WebSocket('ws://' + awshost + ':15674/ws');
}
var client = Stomp.over(ws);
client.connect(username, password, on_connect, on_error, '/');
So the connect via ws: works perfectly fine.
Connect of option 1 to my ELB gets an SSL_ERROR_BAD_CERT_DOMAIN stating that the cert is for myurl.com, ok makes sense
Connect of option 2 to the ec2 instance gets an SSL_ERROR_RX_RECORD_TOO_LONG
Connect of option 3 directly to myurl.com gets a 400 bad request.
port 15674 is open on my ELB with an ssl cert attached.
All ideas on how to get my wss: connection working are appreciated!
Can you check the below and confirm so that I can try to help this one.
Is your certificate generated with AWS ACM?
Have you tried new WebSocket('wss://www.myurl.com:15674/ws');