WebSocket Upgrade Failure PCAP Analysis
How to troubleshoot WebSocket upgrade failures with packet captures, including HTTP 101, Upgrade headers, Connection headers, proxy stripping, TLS, resets, and idle timeouts.
For “WebSocket Upgrade Failure PCAP Analysis”, the short answer is: How to troubleshoot WebSocket upgrade failures with packet captures, including HTTP 101, Upgrade headers, Connection headers, proxy stripping, TLS, resets, and idle timeouts. Treat that statement as a result to verify, not as a promise that every input, device, project, or environment behaves identically. A complete result records the starting state, the exact action, the visible output, and the condition that proves the task is finished in PCAP Surgery.
A site can serve ordinary HTTP normally while its live channel reports “WebSocket connection failed,” an unexpected response code, or a missing 101 Switching Protocols. In the capture, verify the Upgrade and Connection request headers, the proxy's response, TLS completion, and whether a reset occurs before or after the protocol switch; that separates an nginx WebSocket proxy-header problem from an application that closes an established socket. Encrypted payloads may hide header details without keys, but connection timing and TLS records still bound where the failure occurred.
PCAP Surgery is useful because WebSocket traces often need both the HTTP handshake and the post-upgrade TCP timeline preserved.
What a healthy WebSocket upgrade looks like
A client sends an HTTP request with upgrade headers:
GET /socket HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: ...
Sec-WebSocket-Version: 13
The server replies:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: ...
After that, the connection is no longer ordinary HTTP request/response traffic. It carries WebSocket frames.
Common upgrade failures
Common causes include:
- Proxy strips
Upgradeheader. - Proxy strips or rewrites
Connection: Upgrade. - Backend route does not support WebSocket.
- TLS termination sends request to wrong upstream.
- HTTP/2 to HTTP/1.1 upgrade behavior is misconfigured.
- Authentication redirect happens instead of 101.
- Backend returns 400, 403, 404, 426, 502, or 504.
- Connection resets after upgrade.
- Idle timeout closes quiet WebSocket.
The status code and headers matter.
Proxy header problems
Reverse proxies must forward WebSocket upgrade headers correctly. If the backend never sees Upgrade: websocket, it may treat the request as ordinary HTTP.
Packet evidence:
- Client-to-proxy request includes upgrade headers.
- Proxy-to-backend request lacks them.
- Backend returns normal HTTP response instead of 101.
That is a proxy configuration problem, not a WebSocket client bug.
TLS and SNI
For secure WebSocket (wss://), TLS happens before HTTP upgrade. If TLS fails, the WebSocket handshake never begins. Preserve DNS, TCP, TLS ClientHello, SNI, and any TLS alert or reset.
Do not diagnose upgrade headers until the TLS path is proven.
Connection drops after 101
Sometimes upgrade succeeds, then the connection closes. That is a different failure.
Look for:
- FIN or RST sender.
- Idle timeout duration.
- WebSocket ping/pong activity.
- Proxy read timeout.
- TCP retransmissions.
- Zero window.
- Backend process restart.
If the drop happens at a fixed interval, timeout policy is likely.
Checklist
Use this workflow:
- Preserve DNS and TCP connect.
- Verify TLS handshake for
wss://. - Inspect client upgrade request headers.
- Inspect server response status.
- Confirm
101 Switching Protocolsif expected. - Compare client-to-proxy and proxy-to-backend requests.
- Look for redirects or auth responses.
- If upgrade succeeds, inspect post-upgrade FIN/RST/timeout.
- Preserve WebSocket ping/pong timing if visible.
- Trim only after keeping the full handshake.
Final diagnosis
WebSocket upgrade failures are usually HTTP handshake or proxy-forwarding problems until 101 Switching Protocols is proven. After upgrade, failures become long-lived TCP timeout, reset, or application protocol problems.
PCAP Surgery helps preserve both phases so a vague WebSocket error can be traced to headers, proxy behavior, TLS, backend response, or connection lifetime.
Upgrade response decision table
The HTTP status is a routing clue, not the complete diagnosis. Preserve response headers and body where authorized because proxies often include an explanatory error page.
| Response | Common lead | Next evidence |
|---|---|---|
101 |
Upgrade accepted | Post-upgrade frame/close timeline |
301/302/307/308 |
Auth, scheme, or route redirect | Location and client redirect policy |
400 |
Missing/invalid upgrade headers or backend parser | Client-to-proxy and proxy-to-backend headers |
401/403 |
Authentication or origin policy | Token/cookie/origin logs |
404 |
Wrong path or upstream routing | Host/path and proxy route |
426 |
Upgrade required/version mismatch | Protocol/version expectations |
502/503/504 |
Proxy/backend health or timeout | Upstream connection and logs |
A 200 OK often means the request reached an ordinary HTTP route instead of the WebSocket endpoint, or the proxy failed to forward upgrade semantics.
Header-by-header validation
For HTTP/1.1 WebSocket, verify method/path/Host, Upgrade: websocket, Connection token containing Upgrade, Sec-WebSocket-Version: 13, client key, server accept, cookies/auth, and Origin where policy applies. Header names are case-insensitive, but intermediaries can mishandle token lists or hop-by-hop headers.
The Sec-WebSocket-Accept value is derived from the client key; when headers are visible, confirm the response corresponds to the same request. A 101 for another multiplexed/proxied request should not be matched by timing alone.
Is WebSocket Upgrade valid over HTTP/2?
Traditional Connection: Upgrade is HTTP/1.1 behavior. WebSocket over HTTP/2 uses extended CONNECT when supported. A client may negotiate h2 through ALPN while the proxy/backend expects HTTP/1.1 upgrade. Record ALPN and each proxy leg’s protocol.
Why does it work directly but fail through nginx or another proxy?
The proxy may not forward hop-by-hop headers, may route the path to the wrong upstream, may buffer or time out, or may speak a different protocol to the backend. Capture/log client-proxy and proxy-backend legs separately.
Secure WebSocket boundary
For wss://, validate DNS, TCP, SNI, certificate, ALPN, and TLS completion before HTTP. Without authorized TLS keys, do not claim header values or status code from encrypted sizes. Use client/proxy logs and state exactly which source supplied the HTTP outcome.
If TLS closes after ClientHello, follow the TLS handshake failure workflow. If TCP RST appears, use the TCP reset guide.
Post-upgrade frame and close analysis
After 101, preserve both directions, Ping/Pong, Close frames where decoded, TCP FIN/RST, retransmissions, and receive windows. A WebSocket Close frame carries a code/reason before graceful TCP teardown. A TCP RST without Close is a different lifecycle.
| Post-upgrade pattern | Lead |
|---|---|
| 101 then immediate WebSocket Close | Application/auth/protocol policy |
| 101 then RST | Process/proxy abort or invalid frame |
| Fixed quiet interval then FIN/RST | Idle timeout |
| Ping sent, no Pong, then reconnect | Backend/app/path liveness |
| Retransmissions before close | Transport issue may trigger timeout |
| Client closes after malformed frame | Client protocol validation logs |
Which close codes matter?
Codes such as normal closure, going away, protocol error, unsupported data, policy violation, message too big, and internal error narrow application ownership when frames can be decoded. Keep the code and sender, and correlate with endpoint logs.
Idle timeout and heartbeat
Measure from last qualifying traffic to close across several connections. Compare WebSocket Ping/Pong with TCP keepalive and proxy read/send timeouts. A heartbeat must occur with margin before the narrowest infrastructure timer.
Use the TCP keepalive and idle timeout guide for silent drops and fixed intervals. Do not simply increase all timers; validate lifecycle and resource cost.
Proxy-leg matrix
| Client→proxy | Proxy→backend | Interpretation |
|---|---|---|
| Correct Upgrade | Missing Upgrade | Proxy forwarding/config issue |
| 101 received | Backend 101 | Upgrade succeeds end to end |
| 502 returned | Backend connect reset/timeout | Upstream health/path |
| Client RST | Backend remains open | Client-side abort |
| Frontend alive | Backend idle expired | Proxy pool/lifecycle issue |
Correlate legs with request ID, path, Host, and timestamp rather than assuming packet tuples match.
Regression checklist
Test ws:// and wss:// only where supported, intended Host/path, authentication expiry, Origin policy, HTTP/1.1 and HTTP/2 behavior, payload/message-size limits, idle heartbeat, proxy deploy/drain, and reconnect. Verify no duplicate application actions after reconnect.
Require the expected 101, bidirectional message exchange, graceful close behavior, and survival beyond the former idle boundary. Test through the real proxy chain, not only direct backend.
Actionable handoff
Include URL scheme/host/path, DNS result, capture points and proxy legs, TLS SNI/ALPN, visible request/response headers, status, 101 time, first data frame, close code or FIN/RST direction, idle interval, heartbeat behavior, and matching proxy/backend logs.
Preserve DNS through upgrade and the post-upgrade failure. Use capture scope help and the packet preparation workflow. Cookies, URLs, Origin, tokens, and messages require privacy review.
Direct answer: why does a WebSocket return 200 instead of 101?
Usually the request reached an ordinary HTTP handler or an intermediary removed/mishandled upgrade headers. Compare the client request with the proxy-to-backend request and confirm the intended path supports WebSocket.
Worked proxy diagnosis
Assume the browser sends a correct GET /live with Upgrade and Connection headers to a TLS-terminating proxy. The proxy-to-backend request is visible in an authorized decrypted lab capture but lacks both hop-by-hop headers. The backend returns 200 with the normal HTML page, and the proxy forwards it. This proves the browser reached the proxy and the backend route worked as HTTP; the upgrade semantics were lost on the proxy leg.
After correcting configuration, require:
- Client request contains expected host/path/upgrade headers.
- Proxy forwards the required semantics to the intended upstream.
- Backend and client receive matching 101 handshake.
- One bidirectional WebSocket message succeeds.
- Ping/Pong and idle behavior survive beyond the former boundary.
- Graceful Close or documented reconnect occurs during deploy.
What if the response is 403?
Inspect authentication, cookies, token expiry, Origin, CSRF/gateway policy, and whether the WebSocket path has a different authorization rule from normal HTTP. Redact credentials in shared artifacts while preserving status and correlation.
What if the response is 502?
The frontend proxy could not obtain a usable upstream result. Check backend DNS/connect/TLS, health, route, timeout, and whether the upstream expects cleartext HTTP/1.1 or TLS. A 502 does not prove the WebSocket headers were wrong.
Can message size break a connection after upgrade?
Yes. Client, proxy, or backend limits can reject frames/messages or close with a size-related code. Record frame/message size, fragmentation, close sender/code, and configured limits. Also inspect TCP segmentation independently; one WebSocket message need not equal one TCP packet.
Browser and non-browser client differences
Browsers set and restrict certain headers and apply Origin/cookie/security rules. Native clients may use custom headers, proxies, certificate stores, or HTTP stacks. Test the actual client class and version rather than assuming a CLI success reproduces browser behavior.
Monitoring fields that prevent vague alerts
Track upgrade attempts by route, response status, 101 rate, handshake latency, connection duration, close code/sender where available, heartbeat timeout, reconnect rate, backend selection, and client version. Separate “upgrade rejected” from “established then dropped.”
A final support answer should identify the phase: TLS never completed, HTTP returned non-101, proxy lost headers, 101 succeeded but the connection timed out, or application closed a valid WebSocket. Each phase has a different owner.
<!-- multilingual-related-reading:start -->Related guides
Continue with the same-language pages below. They cover adjacent stages without changing the canonical owner of this topic:
<!-- multilingual-related-reading:end -->