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:
-
The Kubernetes Nginx ingress controller is maintained by Kubernetes, and is the one that appears in the Civo app marketplace. I'm using this one.
-
Nginx's ingress controller is one that's maintained by Nginx, and has some differences.
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.