nginx reverse proxy websocket failing

In an application/fleet I have running on balenaCloud (raspberry pi 3B+), I am working on switching from the deprecated zwave integration in home-assistant to the Z-Wave JS integration.

I use home-assistant container, and am working on setting zwavejs2mqtt as another container. I have been using nginx as a reverse proxy to access my home-assistant container, and set up reverse proxy for the zwavejs2mqtt container as well. However, I ran into some interesting issues, that I’ve discussed on the forums at home_assistant (ZwaveJS installation Control Panel - #38 by freshcoast - Z-Wave - Home Assistant Community) and zwavejs2mqtt ([question] Control Panel 'disconnected', but "Zwave driver is ready" · Issue #1539 · zwave-js/zwavejs2mqtt · GitHub).

Basically, the connection to home-assistant container is interfering with the websocket connection in my zwavejs2mqtt container.

Here is an example of my nginx config:

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

upstream homeassistant {
    server sh_homeassistant:8123;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name *.balena-devices.com;

    location / {
        proxy_pass http://homeassistant;
        proxy_set_header Host $host;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location /api/websocket {
        proxy_pass http://homeassistant/api/websocket;
        proxy_set_header Host $host;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location /zwavejs2mqtt {
        rewrite ^ $request_uri;
        rewrite '^/zwavejs2mqtt(/.*)$' $1 break;
        proxy_pass https://zwavejs2mqtt:8091;
        proxy_set_header X-External-Path /zwavejs2mqtt;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

and my docker-compose.yml file:

volumes:
  hass-config:
  backup:
  cgroup:
  store:
  zwave-config:
    name: zwave-config
services:
  sh_homeassistant:
    image: ghcr.io/home-assistant/raspberrypi3-homeassistant:2021.7.4
    restart: unless-stopped
    volumes:
      - 'hass-config:/config'
    ports:
      - 8123
      - 1883
  sh_nginx:
    container_name: sh_nginx
    build: ./sh_nginx
    restart: always
    privileged: true
    ports:
      - 80:80
  zwavejs2mqtt:
    container_name: zwavejs2mqtt
    build: ./zwavejs2mqtt
    restart: always
    tty: true
    stop_signal: SIGINT
    environment:
      - SESSION_SECRET=mysupersecretkey
    devices:
      - "/dev/ttyACM0:/dev/ttyACM0"
    volumes:
      - "store:/usr/src/app/store"
    ports:
      - '8091:8091' # port for web interface
      - '3000:3000' # port for zwave-js websocket server
  sh_pijuice:
    container_name: sh_pijuice
    build: ./sh_pijuice
    restart: on-failure
    privileged: true
    devices:
      - "/dev/i2c-1:/dev/i2c-1"
    volumes:
      - 'hass-config:/hass-config'
      - "cgroup:/sys/fs/cgroup"
    labels:
      io.balena.features.supervisor-api: true
      io.balena.features.dbus: true
      io.balena.features.kernel-modules: true

With this configuration, I can access the zwavejs2mqtt container’s Control Panel successfully initially, using the public device url at path /zwavejs2mqtt, and it connects to its websocket server successfully. I can also connect to the homeassistant container at the public device url, which will connect to its own websocket server connection. However, as soon as I do this, zwavejs2mqtt’s websocket connection stops working.

Any idea what could be going wrong?

I’m also considering switching to traefik, to see if it resolves the issues, but have not worked with it before, and am having some trouble setting it up. I’ve attempted to use setups such as GitHub - klutchell/balena-traefik: traefik stack for balenaCloud to proxy https domains to internal services but am getting 404 errors. Right now, I just want to test an initial config with traefik, and don’t need to implement ssl (may add that if if traefik doesn’t resolve this problem, based on a suggestion from the zwavejs2mqtt devs) - is there a simple guide available that includes routing based on paths, and doesn’t involve setting up ssl?

Hey @kathryn-forsythe, I stopped maintaining GitHub - klutchell/balena-traefik: traefik stack for balenaCloud to proxy https domains to interna a while back and it should probably be archived. Mostly because it required so much manual editing of files and reading the Traefik documentation.

Something I’ve been using more recently with success, and that has support for websockets, is Nginx Proxy Manager. It provides a helpful webUI on port 81 to allow configuration of reverse proxies. Might be worth giving this a try?