Configuring traffic handling for a websockets enabled server application

I’m operating a bit out of my depth trying to expose an RStudio shiny-server web server on my Istio cluster:

client version: 1.4.4
control plane version: 1.5.1
data plane version: 1.5.1 (36 proxies)

I’m able to reach my server using the configuration below, but I’m getting 400 errors for many of the different assets on the server (see images). The server runs without errors in a local docker container.

RStudio has an article outlining how to run shiny server with an nginx and apache proxy, which indicates that websockets forwarding must be correctly configured between the proxy server and shiny server using the below nginx configuration:

http {

  map $http_upgrade $connection_upgrade {
      default upgrade;
      ''      close;
    }

  server {
    listen 80;

    location / {
      proxy_pass http://localhost:3838;
      proxy_redirect / $scheme://$http_host/;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
      proxy_read_timeout 20d;
      proxy_buffering off;
    }
  }
}

I’m hoping that there might be a straightforward way to replicate this configuration with Istio/Envoy. My attempt below has come up short. I’d be grateful for any guidance the community can offer.

apiVersion: istio.banzaicloud.io/v1beta1
kind: MeshGateway
metadata:
  name: shiny-ingress
spec:
  maxReplicas: 1
  minReplicas: 1
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  serviceType: LoadBalancer
  type: ingress
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: shiny
spec:
  selector:
    gateway-name: shiny-ingress
    gateway-type: ingress
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: shiny
spec:
  hosts:
  - "*"
  gateways:
  - shiny
  http:
  - route:
    - destination:
        host: shiny-apps.viq-prod.svc.cluster.local
        port:
          number: 8080
    websocketUpgrade: true
    corsPolicy:
      allowOrigin:
      - "*"
      allowMethods:
      - POST
      - GET
      - OPTIONS
      - CONNECT
      allowCredentials: true
      allowHeaders:
        - Accept
        - Accept-Encoding
        - Accept-Language
        - Cache-Control
        - Connection
        - Cookie
        - Host
        - Origin
        - Pragma
        - Sec-Websocket-Extensions
        - Sec-Websocket-Key
        - Sec-Websocket-Version
        - Upgrade
        - Upgrade-Insecure-Requests
        - User-Agent
      maxAge: "24h"
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
    name: shiny
spec:
    host: shiny-apps.viq-prod.svc.cluster.local
    trafficPolicy:
      loadBalancer:
        consistentHash:
          useSourceIp: true
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: shiny-apps
  labels:
    app: shiny-apps
spec:
  replicas: 1
  selector:
    matchLabels:
      app: shiny-apps
  template:
    metadata:
      labels:
        app: shiny-apps
    spec:
      terminationGracePeriodSeconds: 5
      containers:
      - name: shiny-apps
        image: gcr.io/varianceiq/shiny-apps:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 3838
          name: http
          protocol: TCP
      imagePullSecrets:
        - name: gcr-secret
---
apiVersion: v1
kind: Service
metadata:
  name: shiny-apps
  labels:
    app: shiny-apps
spec:
  ports:
  - name: http
    protocol: TCP
    targetPort: 3838
    port: 8080
  selector:
    app: shiny-apps

It turns out the issue had nothing to do with websockets. Problem was that envoy injects a Content-Length: 0 header that was causing my server to reject the requests. I’ve noticed that this issue has come up some other threads too, so here’s another related post. RStudio is in the process of patching their library

Do you know of a workaround? Upgrading httpuv didn’t do it.

edit: RUN R -e "remotes::install_github(c('rstudio/httpuv'))" actually did fix it