cms.teleglobals.com

How to Configure WebSocket: A Production-Ready Guide 

This guide explains how to configure WebSocket correctly for production environments – covering the HTTP upgrade handshake, NGINX reverse proxy setup, TLS/SSL encryption with WSS, load balancing with sticky sessions, authentication, and the eight practices that separate stable production deployments from configurations that fail under real-world load. It is written for developers, DevOps engineers, and technical architects who are implementing WebSocket-based real-time applications. This guide covers how WebSocket works, a working NGINX configuration, a security checklist, and a framework for deciding when WebSocket is the right protocol for your use case.


Author: Abhinita SinghPublished: 23-Dec-2020

Configuring WebSocket correctly is the difference between a real-time application that handles thousands of concurrent connections and one that drops them silently under load. WebSocket is a persistent, bidirectional communication protocol standardized in RFC 6455. It starts as an HTTP request, upgrades to a dedicated TCP connection, and then allows both the client and server to send messages at any time without repeated HTTP overhead. This guide walks through every configuration step from the initial handshake to production-grade security and scaling. 

For teams planning to deploy WebSocket-based applications in cloud environments, Teleglobal’s DevOps team handles architecture, configuration, and ongoing infrastructure management.

What Is WebSocket? 

WebSocket is a network communication protocol that provides a full-duplex, persistent connection between a client and a server over a single TCP socket. Unlike HTTP, which requires a new request for every piece of data, a WebSocket connection stays open and allows both sides to send messages independently at any time. It operates on port 80 (ws://) for unencrypted connections and port 443 (wss://) for encrypted ones. 

The protocol is defined in RFC 6455 and supported natively in all modern browsers. It is the standard choice for real-time web applications including live chat, financial dashboards, multiplayer games, collaborative editing tools, and IoT monitoring systems. 

WebSocket differs from two commonly confused alternatives: 

  1. HTTP polling: the client repeatedly asks the server “anything new?” on a timer – inefficient and high-latency 
  1. Server-Sent Events (SSE): the server can push data, but the client cannot respond through the same connection – one-way only 
  2. WebSocket: both sides can send at any time – full-duplex bidirectional, persistent, low-overhead 

WebSocket vs HTTP vs SSE: When to Use Each

Choosing the wrong protocol costs weeks of rework. This table maps each protocol to its correct use case. 

Protocol Direction Connection Best For 
WebSocket Bidirectional (both sides) Persistent single TCP connection Live chat, gaming,
collaborative tools, trading dashboards 
HTTP / REST Request-Response New connection per request Standard CRUD operations,
file downloads, stateless APIs 
Server-Sent Events (SSE) Server to client only Persistent HTTP stream Notifications, live feeds, LLM streaming responses, monitoring dashboards 
gRPC Streaming Bidirectional HTTP/2 multiplexed stream Backend service-to-service,
high-throughput, type-safe APIs 
MQTT Pub/Sub Persistent lightweight IoT devices with bandwidth or battery constraints 

How WebSocket Works: Step by Step

Every WebSocket connection starts as an ordinary HTTP/1.1 request. The client sends an Upgrade header asking the server to switch protocols. If the server agrees, both sides switch to the WebSocket protocol and the connection becomes persistent. 

Step 1: Client sends the HTTP Upgrade request

The client sends an HTTP GET request with the headers that trigger the upgrade: 

HTTP PROTOCOL
HTTP Request
Client Request
request.http
GET /chat HTTP/1.1

Host: server.example.com

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Key:
dGhlIHNhbXBsZSBub25jZQ==

Step 2: Server responds with 101 Switching Protocols 

If the server accepts, it replies with HTTP 101: 

HTTP PROTOCOL
HTTP Response
Server Response
response.http
HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept:
s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Step 3: Persistent connection established

After the 101 response, HTTP is done. Both client and server communicate directly using the WebSocket frame format. The connection stays alive until one side explicitly closes it or the network drops it. 

Step 4: Messages exchanged as frames 

Data travels as WebSocket frames – small packets that carry a payload (text or binary), an opcode (message type), and optional masking. The client always masks frames sent to the server. The server never masks responses. This is defined by RFC 6455 and not configurable.

 Configuring NGINX as a WebSocket Reverse Proxy

NGINX has supported WebSocket proxying since version 1.3. In production, NGINX sits in front of your WebSocket server, handles SSL termination, and forwards the upgrade headers. The critical requirement is that NGINX must pass the Upgrade and Connection headers to the upstream, because NGINX drops hop-by-hop headers by default. 

Basic NGINX WebSocket configuration: 

NGINX CONFIGURATION
WebSocket Reverse Proxy
nginx.conf
nginx.conf
upstream websocket_backend {

    server 127.0.0.1:8080;

}

server {

    listen 443 ssl;

    server_name ws.example.com;

    ssl_certificate /etc/ssl/certs/ws.crt;

    ssl_certificate_key /etc/ssl/private/ws.key;

    location /ws {

        proxy_pass http://websocket_backend;

        proxy_http_version 1.1;                    # Required

        proxy_set_header Upgrade $http_upgrade;    # Required

        proxy_set_header Connection "upgrade";     # Required

        proxy_set_header Host $host;

        proxy_set_header X-Real-IP $remote_addr;

        proxy_read_timeout 3600s;

        proxy_send_timeout 3600s;

    }

}

Three lines are mandatory for WebSocket proxying to work. Without proxy_http_version 1.1, NGINX defaults to HTTP/1.0 which does not support the Upgrade mechanism. Without the Upgrade and Connection headers forwarded, the handshake fails silently and the client gets a standard HTTP response instead of a WebSocket connection. The timeout values (3600s = 1 hour) prevent NGINX from closing long-lived idle connections during normal usage. 

WebSocket Security: Always Use WSS in Production

Unencrypted WebSocket connections (ws://) transmit all data in plain text. Any network device between the client and server – proxies, load balancers, ISP infrastructure – can read or modify the content. In production, always use WSS (WebSocket Secure), which runs WebSocket over TLS exactly as HTTPS runs HTTP over TLS. 

Authentication: JWT tokens at the handshake 

WebSocket does not have a native authentication mechanism. The connection upgrade happens via HTTP, so authentication must happen at the handshake stage. The standard approach is to pass a JWT (JSON Web Token) as a query parameter or cookie during the initial HTTP upgrade request, validate it on the server before accepting the upgrade, and reject the connection if it is invalid or expired. Attempting to authenticate after the connection is open is non-standard and difficult to enforce. 

Origin header validation: block CSWSH attacks 

Cross-Site WebSocket Hijacking (CSWSH) is an attack where a malicious website tricks a user’s browser into opening a WebSocket connection to your server using the user’s existing credentials. Defense: validate the Origin header during the handshake. If the Origin does not match your allowed list, reject the connection with HTTP 403 before it upgrades.  

Rate limiting: connections and messages separately 

Rate limit at two levels. First, limit the number of new WebSocket connections per IP per minute at the NGINX layer, using the limit_req_zone directive. Second, implement message-level rate limiting in your application code to prevent a single client from flooding the server with high-frequency messages after connection is established. 

Load Balancing WebSocket Connections 

WebSocket connections are stateful and persistent. Once a client connects to a backend server, all subsequent messages for that session must go to the same server. This makes standard round-robin load balancing unsuitable for WebSocket traffic. 

Sticky sessions (session affinity) – required 

Sticky sessions ensure each client always routes to the same backend server. In NGINX, this is implemented with ip_hash (routes based on client IP) or with cookie-based affinity in NGINX Plus. The ip_hash method is sufficient for most deployments. Cookie-based affinity is more precise when clients share IP addresses (e.g. behind a corporate NAT). 

NGINX CONFIGURATION
WebSocket Upstream Configuration
nginx.conf
nginx.conf
upstream websocket_backend {

    ip_hash;            # sticky sessions - required for WebSocket

    server ws1.internal:8080;

    server ws2.internal:8080;

}

least_conn for idle-heavy workloads

For applications where WebSocket connections are long-lived but mostly idle (monitoring dashboards, notification systems), use least_conn instead of ip_hash. This distributes new connections to the server with fewest active connections, preventing one server from accumulating too many long-lived but low-activity sessions. 

WebSocket Best Practices for Production 

These eight practices apply to every WebSocket deployment regardless of language, library, or cloud provider. 

  • Send heartbeats every 25-30 seconds. WebSocket connections can be silently dropped by intermediate proxies, firewalls, and cloud load balancers that terminate idle TCP connections. A ping frame from server to client (or client to server) resets inactivity timers. A heartbeat that is never sent is a connection that silently fails. 
  • Implement exponential backoff on the client for reconnections. When a connection drops, the client should wait 1 second before the first retry, then 2, 4, 8 seconds – up to a maximum (e.g. 30 seconds). All clients reconnecting simultaneously after a server restart creates a connection storm. Jitter (a random ±20% delay) spreads the load. 
  • Build a protocol layer on top of raw WebSocket. RFC 6455 gives you a transport. It gives you nothing for message ordering, acknowledgment, topic routing, or error codes. Define a simple JSON envelope ({type, payload, id}) so both sides understand message structure. 
  • Set maximum message size limits. Without limits, a malicious client can send a single large message and exhaust server memory. Set maxPayload in your ws library configuration and enforce it server-side. 
  • Use wss:// (port 443) in production, always. Port 443 also passes through firewalls and proxies that block non-standard ports. Port 80 (ws://) is unencrypted and should never carry sensitive data. 
  • Handle backpressure. If your server generates messages faster than a client can consume them, the buffer grows without limit. Monitor the bufferedAmount property on the client side and pause sending when it exceeds a threshold. 
  • Separate WebSocket servers from your HTTP API servers in high-load environments. WebSocket connections are long-lived and consume a file descriptor for their entire duration. Thousands of concurrent connections exhaust file descriptor limits (ulimit). Dedicated WebSocket servers let you tune OS-level limits independently. 
  • Test with network interruption tools before production launch. Simulate connection drops, slow networks, and reconnection storms. Tools: wscat for manual testing, Artillery for load testing WebSocket endpoints. An untested reconnection strategy is not a strategy. 

WebSocket on Cloud: AWS, Azure, and Google Cloud 

All three major cloud platforms support WebSocket with native managed services.

Platform WebSocket Service Best For Note 
AWS API Gateway WebSocket APIs, ALB (Application Load Balancer) Serverless WebSocket apps, microservice routing ALB supports sticky sessions natively 
Azure Azure SignalR Service, Azure Application Gateway SignalR abstracts WebSocket; auto-scales to millions of connections SignalR falls back to SSE or long-polling automatically 
Google Cloud Cloud Run (WebSocket supported natively), Cloud Load Balancing Container-based WebSocket deployments Increase request timeout; disable HTTP/2 end-to-end on Cloud Run 

How Teleglobal Can Help with Your WebSocket Infrastructure

Correctly configuring WebSocket for production involves more than the NGINX directives above. It requires choosing the right cloud service, designing reconnection and backpressure handling, integrating authentication, setting up monitoring for connection counts and message throughput, and load testing before launch. 

Teleglobal International’s infrastructure and DevOps team has designed and deployed real-time application infrastructure across AWS, Azure, and Google Cloud for clients in India, UAE, the US, and Europe. The team handles WebSocket architecture reviews, NGINX configuration, cloud load balancer setup, and ongoing monitoring as part of managed DevOps engagements.  

Frequently Asked Questions

1. What is WebSocket and how does it work?

WebSocket is a communication protocol defined in RFC 6455 that creates a persistent, bidirectional TCP connection between a client and server. It starts as an HTTP/1.1 request with an Upgrade header. When the server responds with HTTP 101, both sides switch to the WebSocket protocol and can send messages independently at any time without the overhead of repeated HTTP requests. 

2. How do I configure WebSocket in NGINX? 

Set proxy_http_version to 1.1 and pass the Upgrade and Connection headers to the upstream. Without these three directives, NGINX drops the upgrade headers and the WebSocket handshake fails. Also set proxy_read_timeout and proxy_send_timeout to at least 3600 seconds to prevent NGINX from closing idle long-lived connections prematurely. 

3. What is the difference between ws:// and wss://? 

ws:// is an unencrypted WebSocket connection running on TCP port 80. wss:// (WebSocket Secure) runs on TCP port 443 and encrypts all data with TLS, the same encryption layer used by HTTPS. In production, always use wss://. Unencrypted ws:// exposes all transmitted data to any network device between client and server, including proxies, ISPs, and load balancers. 

4. What is a WebSocket handshake? 

The WebSocket handshake is the initial HTTP/1.1 exchange that upgrades the connection from HTTP to WebSocket. The client sends a GET request with Upgrade: websocket, Connection: Upgrade, and a Sec-WebSocket-Key header. The server responds with HTTP 101 Switching Protocols and a Sec-WebSocket-Accept value. After that exchange, HTTP is done and WebSocket frames begin flowing. 

5. How do I load balance WebSocket connections? 

WebSocket connections are stateful – all messages for a session must go to the same backend server. Use sticky sessions (session affinity) in your load balancer. In NGINX, add ip_hash to the upstream block. In AWS ALB, enable target group stickiness. In HAProxy, use balance source. Standard round-robin load balancing breaks WebSocket sessions when requests route to different servers. 

6. What is the difference between WebSocket and Server-Sent Events? 

WebSocket is bidirectional – both client and server can send messages at any time. Server-Sent Events (SSE) are unidirectional – only the server can push data; the client cannot respond through the same connection. Use WebSocket for live chat, gaming, and collaborative tools where both sides exchange data. Use SSE for notifications, dashboards, and LLM streaming responses where only the server pushes updates. 

7. What port does WebSocket use? 

WebSocket uses port 80 for unencrypted connections (ws://) and port 443 for encrypted connections (wss://). These are the same ports as HTTP and HTTPS. Using port 443 means WebSocket traffic passes through firewalls and proxies that block non-standard ports. Never expose ws:// on any port in production – use wss:// on port 443 only. 

8. What are the most common WebSocket configuration mistakes in production? 

Five most common mistakes: not passing Upgrade and Connection headers in the NGINX proxy configuration (connection fails silently), not setting sticky sessions in the load balancer (sessions break on reconnect), not implementing heartbeat ping-pong (connections silently drop through firewalls), using ws:// instead of wss:// (data is unencrypted), and not validating the Origin header at handshake (CSWSH vulnerability).