Search code examples
amazon-web-serviceswebsocketamazon-ecsamazon-cloudfrontaws-nlb

WebSockets through CloudFront + NLB to ECS Fargate (NestJS)


I have a part of my application which is designed to handle websocket connection from my React frontend using socket.io

Issue

I've set everything up and now I have an issue where HTTP handshake attempt from socket.io-client gets status 400 as response, and if I try to use directly WebSocket transport I see only repeating Finished status in Network Tab

Setup

My backend setup: Docker > NestJS (socket.io)

My AWS setup: CloudFront > NLB > ECS Fargate

My frontend setup: React + socket.io

Additional Info

NestJS logs in CloudWatch are pure, the last one: NestJS successfully started Expected last: Connected: user id after reaching endpoint in my frontend

I've tested connection of NestJS container by navigating in browser to / root path using CloudFront domain name, and it works well - returns Hello World page as it should, so the NestJS server is running

Also locally tested my NestJS with and without container - everything works as expected, so the issue is somewhere in AWS Infrastructure

Starting from the bottom, my configs:

NestJS

NestJS runs at port 80

WebSocket Gateway inherits port 80, no namespace defined

Docker

Docker exposes port 80

ECS

ECS Task Definition port mapping - 80:80 TCP

ECS Service (NestJS container) Security Group: Allowed All TCP:0-65535 traffic from NLB

NLB

NLB Security Group 1: IPv4 HTTPS TCP:443. from 0.0.0.0/0 (just in case)

NLB Security Group 2: IPv4 HTTP TCP:80. from 0.0.0.0/0

NLB Listener set up as TCP:80 to Target Group which contains service which runs NestJS container

CloudFront

CloudFront Security Policy: TLSv1.2_2021

CloudFront Supported HTTP versions: HTTP/2, HTTP/1.1, HTTP/1.0

CloudFront terminates TSL and routes traffic to NLB using TCP:80 although by itself accepts 443 (HTTP only to > NLB)

CloudFront strategy: Redirect HTTP to HTTPS (incoming)

IMPORTANT UPDATE: Connected to NLB avoiding CloudFront - works. Issue is somewhere in CloudFront


Solution

  • Solved!

    I should've attach Cache Policy which allows to preserve headers (Origin, Host, Authorization in my case) and connection has been established successfully.

    CloudFront, select Policies at the left menu

    Under "Custom Policies" click "Create cache policy"

    Under the "Cache key settings" select "Include the following headers" and include headers you need Also I've added query strings: All

    Then attach Policy at the "Origins" tab inside the "Origin Settings"