Using websockets with the NGINX Kubernetes ingress controller

Learn how to set up WebSockets with the NGINX ingress controller in Civo Kubernetes to avoid the error code 426 Upgrade Required.

2 minutes reading time

Written by

Civo Team
Civo Team

Marketing Team @ Civo

As I spent more than two days figuring out how to set up websockets to work with NGINX ingress controller in Civo Kubernetes, I thought I would write it down to save others time. This allows you to get past error code 426 Upgrade Required which you may encounter.

Important note:

There are multiple flavors of NGINX Kubernetes ingress controllers available:

Getting around NGINX WebSocket “error 426 upgrade required”

I followed different articles and Stack Overflow links for the solution, but every time I thought it should work, I was getting HTTP error code 426, "Upgrade Required". The connection did not upgrade itself by the NGINX load balancer.

After some help with Amit, I realized that we need to insert some configuration in the location block of NGINX to upgrade the connections for websockets.

Here are some snippets for an example:

  • deployment.yaml file:
apiVersion: apps/v1
kind: Deployment
metadata:
name: tornado-socket
labels:
app: tornado-socket
group: testing
spec:
replicas: 1
selector:
matchLabels:
app: tornado-socket
template:
metadata:
labels:
app: tornado-socket
group: testing
spec:
containers:
- name: tornado-socket
image: ajayinnvonix/tornado-demo
ports:
- name: websocket
containerPort: 8000
  • service.yaml file:
apiVersion: v1
kind: Service
metadata:
name: tornado-socket
labels:
app: tornado-socket
group: testing
spec:
type: ClusterIP
selector:
app: tornado-socket
ports:
- name: websocket
protocol: TCP
port: 8000
targetPort: 8000
  • ingress.yaml file:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tornado-socket
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/server-snippets: |
location / {
proxy_set_header Upgrade $http_upgrade;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_set_header Connection "upgrade";
proxy_cache_bypass $http_upgrade;
}
spec:
ingressClassName: nginx
rules:
- host: tornado-ws.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tornado-socket
port:
number: 8000

The part in nginx.ingress.kubernetes.io/server-snippets is what actually upgrades the connection.

Wrapping up

I tested it on my local system with a simple node websocket server behind NGINX, and without the upgrade headers, I was getting the error 426, even on directly passing proxy to the Node upstream. Once the upgrade headers are set, the error disappears.

References

Civo Team
Civo Team

Marketing Team @ Civo

Civo is the Sovereign Cloud and AI platform designed to help developers and enterprises build without limits. We bridge the gap between the openness of the public cloud and the rigorous security of private environments, delivering full cloud parity across every deployment. As a team, we are dedicated to providing scalable compute, lightning-fast Kubernetes, and managed services that are ready in minutes. Through CivoStack Enterprise and our FlexCore appliance, we empower organizations to maintain total data sovereignty on their own hardware.

Our mission is to make the cloud faster, simpler, and fairer. By providing enterprise-grade NVIDIA GPUs and streamlined model management, we ensure that high-performance AI and machine learning are accessible to everyone. Built for transparency and performance, the Civo Team is here to give you total control over your infrastructure, your data, and your spend.

View author profile