This is something that took me nearly a year to get working. Not full time obviously, but every now and then I would make another attempt at getting it working after the trauma of the previous attempt had faded. None of the examples that people had provided worked for me, and some were out dated and no longer applied. And of course the AWS documentation provided no help whatsoever.

Update December 12th 2021
This article only applies to Elastic Beanstalk environments using the old ‘Node.js running on 64bit Amazon Linux’ platform branch. Websockets work by default for Amazon Linux 2 environments.

I decided to share my configuration in the hope that it will help someone else. Here is a list of the technologies I am using:

On the server

The node app on the server runs Express, and I have condensed the critical lines into the following to show the Socket.io setup:

const http = require('http');
const express = require('express');
const socketio = require('socket.io');

const app = express();
const server = http.createServer(app);
const io = socketio(server);

io.on('connection', (socket) => {
  // client connected
});

server.listen(3000); // whatever port you are using

On the client

On the client side I have the following to connect to Socket.io on the server:

const io = require('socket.io-client');
const socket = io(window.location.host);

socket.on('connect', () => {
  console.log("connected to server");
});

Elastic Beanstalk config

Up until now this should all be standard Socket.io configuration. Note that there is no messing around with port numbers, it should work on whatever port/domain your app is using.

The tricky part is getting the WebSockets to work with the load balancer, and the Nginx reverse proxy. Make sure you use the Application Load Balancer, not the ‘Classic’ load balancer. The Application load balancer natively supports WebSockets (and HTTP2), however AWS is not very clear on how to actually make them work.

After probably hundreds of Google searches and reading the the same articles over and over again nothing seemed to work. I eventually stumbled upon an AWS blog post – How to Build a Chat Application with Amazon ElastiCache for Redis. At the very bottom of the post there is one small piece of gold which finally after nearly a year got WebSockets working. The mysterious ‘working’ .ebextensions config!

And here it is:

container_commands:
  enable_websockets:
    command: |
      sed -i '/\s*proxy_set_header\s*Connection/c \
              proxy_set_header Upgrade $http_upgrade;\
              proxy_set_header Connection "upgrade";\
      ' /tmp/deployment/config/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf

Place this little gem into your .ebextensions/ folder, I called mine socketupgrade.config.

The re-deploy you app and hopefully you will have working WebSockets!