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: extensions/v1beta1
kind: Ingress
metadata:
 name: tornado-socket
 annotations:
  kubernetes.io/ingress.class: nginx
  nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
  nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
  nginx.ingress.kubernetes.io/server-snippets: |
   location / {
    proxysetheader Upgrade $httpupgrade;
    proxyhttpversion 1.1;
    proxysetheader X-Forwarded-Host $httphost;
    proxysetheader X-Forwarded-Proto $scheme;
    proxysetheader X-Forwarded-For $remoteaddr;
    proxysetheader Host $host;
    proxysetheader Connection "upgrade";
    proxycachebypass $httpupgrade;
    }
spec:
 rules:
  - host: tornado-ws.example.com
   http:
    paths:
     - backend:
       serviceName: tornado-socket
       servicePort: 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