HTTP is a request and an answer: the client asks, the server replies. A WebSocket is a channel where both sides can talk at any time. The standard, RFC 6455, says it "enables two-way communication" between a client and a host. Every WebSocket starts life as an HTTP request, though, and that is where proxies come in.
We sent a WebSocket through 12 free proxies on 11 October 2026 and counted what one message costs on each protocol. The encrypted kind, wss://, got through 8 of them. The plain kind, ws://, got through 3.
How does a WebSocket start?
With an ordinary HTTP request that asks to switch protocols. RFC 6455 designed it that way on purpose: the handshake "is intended to be compatible with HTTP-based server-side software and intermediaries". This is the request our test client sent:
GET / HTTP/1.1
Host: echo.websocket.org
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: <16 random bytes, base64>
Sec-WebSocket-Version: 13
The server agrees with status 101. In RFC 9110's words, it "indicates that the server understands and is willing to comply" with the switch. From then on, the same connection carries WebSocket frames, not HTTP. RFC 6455 describes it as "a two-way communication channel where each side can, independently from the other, send data at will".
What is the actual difference?
| HTTP | WebSocket | |
|---|---|---|
| Who can send | The client asks, the server answers | Either side, at any time |
| Connection | Kept open for more requests in HTTP/1.1 | Kept open for the whole session |
| Cost of one 14-byte message | 99 bytes of request headers, 233 of response headers | 20 bytes out, 16 bytes back |
| On HTTP/2 and HTTP/3 | Yes | Yes, over one stream (RFC 8441, RFC 9220) |
| Through a forward proxy | Always, it is what proxies carry | wss:// through CONNECT; ws:// only if the proxy passes Upgrade |
One common claim is wrong. Several guides say HTTP opens a new connection for every request. RFC 9112 says the opposite: "HTTP/1.1 defaults to the use of 'persistent connections', allowing multiple requests and responses to be carried over a single connection." The real difference is not the connection. It is who may speak on it.
What does one message cost?
Our client sent the same 14-byte message both ways. As a WebSocket frame it took 20 bytes: 2 bytes of header, a 4-byte mask, and the message. RFC 6455 requires the mask in one direction: "All frames sent from the client to the server are masked by a 32-bit value that is contained within the frame." The echo came back in 16 bytes, since server frames carry no mask.
As an HTTP request to the same server, the same message needed 99 bytes of request headers, and the answer brought 233 bytes of headers. That is the price of HTTP's flexibility: every request carries its own description. For a chat or a price feed with many small messages, the frame wins. For loading a page or calling an API now and then, the difference does not matter.
What happens behind a forward proxy?
This is where the two kinds of WebSocket part ways. We tried both through 12 free HTTP proxies from our own list:

The reason is one header. nginx's documentation explains it: "since the 'Upgrade' is a hop-by-hop header, it is not passed from a client to proxied server. With forward proxying, clients may use the CONNECT method to circumvent this issue."
With wss://, the client asks the proxy for a tunnel, and the proxy relays encrypted bytes it cannot read. The WebSocket handshake travels inside. With ws://, the proxy has to understand the Upgrade request and pass it on, and most of ours did not. So use wss:// whenever a proxy sits in the path. Our residential proxies carry wss:// through CONNECT like any HTTPS site.
What happens behind a reverse proxy?
A reverse proxy in front of a WebSocket server needs two things set up. First, it has to forward the Upgrade and Connection headers explicitly, since they are hop-by-hop. Second, it may close quiet connections. nginx's default: "the connection will be closed if the proxied server does not transmit any data within 60 seconds". That is a common reason for WebSockets that drop after a minute. The server can send ping frames to keep the line busy, or the timeout can be raised. We explain the reverse proxy itself in reverse proxy vs load balancer.
When are server-sent events enough?
When only the server talks. MDN describes server-sent events as a way for "a server to send new data to a web page at any time, by pushing messages to the web page". They run over plain HTTP, with no protocol switch. A live score or a notification feed rarely needs more. A chat, a game or a trading screen where the client also sends often is where a WebSocket pays off.
What this page could not check
- 12 free proxies from our own list, one run, two public echo servers. Paid and corporate proxies were not tested.
- The client was our own small program, not a browser's WebSocket code.
- The byte counts use one minimal HTTP request. Browsers send more headers than that.
- A 502 can come from the proxy or from something behind it. From outside, the two look the same.
- Free proxies change within hours. We will run the test again by 11 January 2027.
Sources
- RFC 6455, The WebSocket Protocol, IETF, December 2011: rfc-editor.org.
- RFC 9110, HTTP Semantics, Upgrade and 101 Switching Protocols, IETF, June 2022: rfc-editor.org.
- RFC 9112, HTTP/1.1, persistent connections, IETF, June 2022: rfc-editor.org.
- RFC 8441, Bootstrapping WebSockets with HTTP/2, IETF, September 2018: rfc-editor.org.
- RFC 9220, Bootstrapping WebSockets with HTTP/3, IETF, June 2022: rfc-editor.org.
- MDN Web Docs, The WebSocket API, read 11 October 2026: developer.mozilla.org.
- MDN Web Docs, Server-sent events, read 11 October 2026: developer.mozilla.org.
- nginx, WebSocket proxying, read 11 October 2026: nginx.org.
- Our own test on our server, 11 October 2026, 08:26 UTC: ws_test.py through 12 free proxies, and the byte counts.



