Kubernetes - SignalR Behind Ingress Connection Disconnected With 1006
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
WebSocket close code 1006 means the client observed an abnormal connection closure without receiving a proper close frame. When SignalR runs behind Kubernetes ingress, that usually points to a proxy or routing problem rather than a bug in SignalR itself. The most common causes are proxy timeouts, missing WebSocket support, pod churn, or load balancing that breaks a long-lived SignalR connection.
Why This Happens Behind Ingress
A SignalR connection is long-lived and stateful. An ingress controller or external load balancer sits between the browser and the pod, so several extra failure modes appear:
- idle or read timeout closes the socket
- WebSocket upgrade headers are not handled correctly
- requests from one client hit different pods unexpectedly
- the backend pod restarts or is drained during rollout
- the external load balancer closes idle TCP sessions first
Code 1006 is not very specific by itself. It tells you the close was abnormal, not exactly which proxy layer did it.
Start With the Proxy Timeouts
Ingress defaults are often tuned for short HTTP requests, not for persistent WebSocket sessions. If the connection is closed at a fixed interval, timeout settings are the first thing to inspect.
For ingress-nginx, long-lived SignalR traffic often needs larger proxy timeouts:
These values are examples, not universal constants. The point is that WebSocket traffic often needs much longer read and send windows than ordinary REST endpoints.
Check Session Affinity and Routing Behavior
If you are self-hosting SignalR across multiple pods, connection routing matters. A client negotiates and then expects its ongoing transport to stay coherent. If different requests for the same session are routed inconsistently, disconnects and handshake failures can appear.
Possible fixes include:
- enabling sticky sessions at the ingress layer
- using a SignalR backplane or Azure SignalR Service for multi-instance fan-out
- making sure negotiation and transport requests hit compatible backends
An ingress-nginx cookie-affinity example:
Affinity is not always required, but in self-hosted multi-pod setups it is a common missing piece.
Verify the Application and Transport Settings
SignalR itself should also be configured for the deployment reality. If keepalive and timeout settings are too aggressive relative to proxy behavior, connections can flap unnecessarily.
A server-side example in ASP.NET Core:
These settings do not fix a bad ingress by themselves, but they help the server and client detect dead connections in a predictable way.
Look for Pod Restarts and Rollouts
A 1006 that appears during deployments or scale events is often not an ingress annotation problem at all. It may simply be that the SignalR pod is restarting, being rescheduled, or being terminated during a rollout.
Check:
If the disconnects line up with pod replacement, then graceful shutdown, readiness, and rollout strategy matter just as much as WebSocket configuration.
Confirm WebSocket Support End to End
The full path has to support WebSockets:
- browser or client library
- ingress controller
- Kubernetes service
- pod
- any external load balancer in front of ingress
A surprising number of 1006 issues are really on the external load balancer side. The ingress might be configured correctly, but the cloud load balancer in front of it closes idle connections sooner than expected.
That is why you should inspect logs at multiple layers:
- browser console
- SignalR server logs
- ingress controller logs
- cloud load balancer or gateway metrics if available
Common Pitfalls
The biggest mistake is treating 1006 as a SignalR-only error. It is often a proxy or network-lifecycle problem.
Another mistake is increasing only the client timeout while leaving ingress read and send timeouts low. The outer proxy closes the connection first, so the application-level setting never gets a chance to help.
Teams also often scale SignalR to multiple pods without thinking about affinity or backplane design. Long-lived real-time connections need more routing care than stateless HTTP requests.
Finally, do not ignore deployments and pod churn. If a disconnect happens exactly when pods rotate, investigate rollout behavior before changing every ingress annotation in sight.
Summary
- WebSocket
1006behind ingress usually means an abnormal close caused by a proxy, routing, or pod-lifecycle issue. - Start with ingress and load-balancer timeout settings for long-lived connections.
- In multi-pod self-hosted SignalR setups, check affinity or backplane strategy.
- Verify SignalR keepalive settings, but do not expect them to compensate for broken proxy behavior.
- Correlate disconnect timing with ingress logs, load-balancer behavior, and pod restarts.
Related reading
- Kubernetes - use local hard drive as persistent volume
- Kubernetes - wait for other pod to be ready
- Kubernetes - what does unset mean in port in a service?
- kubernetes / Best practice to inject values to configMap
- Kubernetes / kubectl - A container name must be specified but seems like it is?
- Kubernetes , liveness probe is failing but pod in Running state
- Kubernetes and insecure registry
- Kubernetes API - Get Pods on Specific Nodes

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.