Title: docker-compose deploy has no wiring for the buzz-pair-relay sidecar — mobile QR pairing 404s out of the box
Body:
Mobile QR pairing failed with WebSocket connection failed: HTTP error: 404 Not Found on a self-hosted relay deployed via deploy/compose/ (plain Docker Compose, not the Helm chart).
Root cause: the relay's NIP-11 doc advertised NIP-43 support (membership-enforcing relay, correctly per crates/buzz-relay/src/nip11.rs's own test suite intent), which makes the desktop client (desktop/src-tauri/src/commands/pairing.rs::pairing_relay_from_nip11) infer a /pair legacy-path sidecar — but deploy/compose/ never stands one up. There's no /pair route anywhere in the stack (bare reverse_proxy relay:3000 catch-all in the example Caddyfile), and no buzz-pair-relay service in deploy/compose/compose.yml. The relay's own test comment (nip11.rs) even predicts this exact failure mode: "advertising it on open relays misroutes pairing peers to a non-existent /pair sidecar."
By contrast, deploy/charts/buzz/templates/pairing-relay.yaml (Helm) does wire this up correctly — but it's pairingRelay.enabled: false by default there too, so it's easy to end up with a relay that advertises NIP-43 without a working pairing sidecar on either deploy path.
We worked around it by hand for our own compose deployment:
- Added a
pairing-relay service to compose.yml using the same ${BUZZ_IMAGE}, with entrypoint: ["/usr/local/bin/buzz-pair-relay"] (worth noting: Compose's command: only appends args to the image's baked-in ENTRYPOINT ["/usr/local/bin/buzz-relay"], unlike Kubernetes where command: replaces it — so copying the Helm chart's command: pattern into Compose silently runs the wrong binary; needed entrypoint: instead)
handle_path /pair* { reverse_proxy pairing-relay:5000 } in the Caddyfile
BUZZ_PAIRING_RELAY_URL=wss://<domain>/pair on the relay service, so NIP-11 advertises pairing_relay_url directly instead of relying on the NIP-43 inference path
Ask: add the pairing-relay service + Caddyfile route to deploy/compose/compose.yml/Caddyfile (or the example files), matching what the Helm chart already does, so a membership-enforcing compose deployment doesn't advertise a pairing capability it can't serve.
Secondary observation, lower confidence: the first pairing attempt after standing up the sidecar failed with "Lost connection to pairing relay" in the desktop app, even though both devices displayed and matched the same SAS code — it worked cleanly on retry. handle_nip42_auth (pairing.rs) waits up to 3s for an AUTH challenge from the relay before subscribing; buzz-pair-relay never sends one (it's a bare relay, no NIP-42), so both sides burn a fixed ~3s stall before their REQ subscription goes out. Against an ephemeral, non-buffered relay (no event replay), that's a plausible race window if one side's event arrives before the other side's subscription is live. Not confirmed as the root cause, but worth a look if this is reproducible elsewhere — happy to provide sidecar logs from the one reproduction we have.
Title: docker-compose deploy has no wiring for the
buzz-pair-relaysidecar — mobile QR pairing 404s out of the boxBody:
Mobile QR pairing failed with
WebSocket connection failed: HTTP error: 404 Not Foundon a self-hosted relay deployed viadeploy/compose/(plain Docker Compose, not the Helm chart).Root cause: the relay's NIP-11 doc advertised NIP-43 support (membership-enforcing relay, correctly per
crates/buzz-relay/src/nip11.rs's own test suite intent), which makes the desktop client (desktop/src-tauri/src/commands/pairing.rs::pairing_relay_from_nip11) infer a/pairlegacy-path sidecar — butdeploy/compose/never stands one up. There's no/pairroute anywhere in the stack (barereverse_proxy relay:3000catch-all in the example Caddyfile), and nobuzz-pair-relayservice indeploy/compose/compose.yml. The relay's own test comment (nip11.rs) even predicts this exact failure mode: "advertising it on open relays misroutes pairing peers to a non-existent /pair sidecar."By contrast,
deploy/charts/buzz/templates/pairing-relay.yaml(Helm) does wire this up correctly — but it'spairingRelay.enabled: falseby default there too, so it's easy to end up with a relay that advertises NIP-43 without a working pairing sidecar on either deploy path.We worked around it by hand for our own compose deployment:
pairing-relayservice tocompose.ymlusing the same${BUZZ_IMAGE}, withentrypoint: ["/usr/local/bin/buzz-pair-relay"](worth noting: Compose'scommand:only appends args to the image's baked-inENTRYPOINT ["/usr/local/bin/buzz-relay"], unlike Kubernetes wherecommand:replaces it — so copying the Helm chart'scommand:pattern into Compose silently runs the wrong binary; neededentrypoint:instead)handle_path /pair* { reverse_proxy pairing-relay:5000 }in the CaddyfileBUZZ_PAIRING_RELAY_URL=wss://<domain>/pairon therelayservice, so NIP-11 advertisespairing_relay_urldirectly instead of relying on the NIP-43 inference pathAsk: add the pairing-relay service + Caddyfile route to
deploy/compose/compose.yml/Caddyfile(or the example files), matching what the Helm chart already does, so a membership-enforcing compose deployment doesn't advertise a pairing capability it can't serve.Secondary observation, lower confidence: the first pairing attempt after standing up the sidecar failed with "Lost connection to pairing relay" in the desktop app, even though both devices displayed and matched the same SAS code — it worked cleanly on retry.
handle_nip42_auth(pairing.rs) waits up to 3s for an AUTH challenge from the relay before subscribing;buzz-pair-relaynever sends one (it's a bare relay, no NIP-42), so both sides burn a fixed ~3s stall before theirREQsubscription goes out. Against an ephemeral, non-buffered relay (no event replay), that's a plausible race window if one side's event arrives before the other side's subscription is live. Not confirmed as the root cause, but worth a look if this is reproducible elsewhere — happy to provide sidecar logs from the one reproduction we have.