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.

Your Alt Text

References