Configuring WebSockets on Elastic Beanstalk/EC2

July 15, 2018

Here's a quick-and-dirty guide to configuring WebSockets on an AWS EC2 instance/Elastic Beanstalk.

Without any configuration on EC2, the client side will be unable to connect to a WebSocket on the server.

WebSockets allow two-way communication between client and server.

The WebSocket protocol consists of an opening handshake followed by bidirectional messages layered over TCP. The handshake is the bridge from HTTP to WS. The client sends a run-of-the-mill get request with headers that look like these:

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

If the negotiation is successful the WS server responds with something like:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

For WS to work on elastic beanstalk/EC2, the server must listen for incoming socket connections using a standard TCP socket.

The first step to running a WebSocket server on EC2/Elastic Beanstalk is setting the protocol to TCP (rather than HTTP) and listening on PORT 80.

Security Group Configuration 

Next, navigate to EC2 > Network & Security > Security Groups.

Select the security group that's associated with your EC2 instance, click the Inbound tab, and click edit.

You'll need to add a rule that looks something like the following:

The type should be HTTP, the protocol TCP, the PORT 80, and the source Anywhere (or 0.0.0.0/0, ::/0).

NGINX Configuration

When a WS client issues a handshake request, the WS server needs to respond with the right headers. For example, the server needs to respond with:

Upgrade: websocket
Connection: Upgrade

With Elastic Beanstalk, EC2 instances are transient. Therefore imparting the right NGINX config to one particular box is insufficient. Instead, we can write a recipe with pre- and post-deploy hooks. Creating a hook is as simple as adding a file in your_project_root/.ebextensions/my_config_file.config.

In the example below, we tell Elastic Beanstalk to create two new files. The first lives at/etc/nginx/conf.d/01_websockets.conf on the EC2 instance. The contents are an NGINX configuration file that sets the Upgrade and Connection headers.

The second file is bash script that renames the default Elastic Beanstalk NGINX proxy configuration file so that we use the new one.