block / block/buzz

`deploy/compose` is missing two pieces the Helm chart has: desktop clients can't connect, and mobile pairing 404s

Open
#3,291 1 comment 1 reaction 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

Standing up a fresh single-node relay by following `deploy/compose/README.md` produces a relay that the official desktop app cannot join, and whose "Pair Mobile Device" flow always fails. Both are gaps between `deploy/compose` and `deploy/charts/buzz`, and both surface as misleading errors that point away from the real cause.

Relay image: `ghcr.io/block/buzz:sha-3a4bf51`. Deployment: `deploy/compose` with `BUZZ_COMPOSE_TLS=true`, unmodified `.env.example` values except secrets and domain.

---

## 1. `.env.example` omits the desktop app's origin from `BUZZ_CORS_ORIGINS`

`deploy/compose/.env.example` sets:

```
BUZZ_CORS_ORIGINS=https://buzz.example.com
```

The Tauri desktop app's webview origin is `tauri://localhost`, so every REST call it makes is blocked by the browser. `AddCommunityDialog` → "Join an existing community" fails with **"Load failed"** — WebKit's generic fetch error. No WebSocket is ever opened, so the relay logs show zero connection attempts, which makes it look like an auth or network problem rather than CORS.

Reproduce against a relay deployed from the bundle:

```bash
# Allowed origin — header present
curl -sD- -o /dev/null -H "Origin: https://relay.example.com" \
https://relay.example.com/api/join-policy | grep -i access-control-allow-origin
# access-control-allow-origin: https://relay.example.com

# Desktop app's actual origin — no header, browser blocks the response
curl -sD- -o /dev/null -H "Origin: tauri://localhost" \
https://relay.example.com/api/join-policy | grep -i access-control-allow-origin
# (nothing)
```

`crates/buzz-relay/src/config.rs` already documents `tauri://localhost` as the expected value, so this looks like the example file simply drifted from the code comment.

**Suggested fix** — add the app origins to `.env.example`:

```
BUZZ_CORS_ORIGINS=https://buzz.example.com,tauri://localhost,http://tauri.localhost,https://tauri.localhost
```

---

## 2. The bundle advertises NIP-43 but ships no pairing sidecar, so `/pair` 404s

`deploy/charts/buzz` deploys `buzz-pair-relay` as its own workload (`templates/pairing-relay.yaml`) and wires `BUZZ_PAIRING_RELAY_URL`. `deploy/compose` has neither, but the main relay still advertises NIP-43 in its NIP-11 document.

`desktop/src-tauri/src/commands/pairing.rs::resolve_pairing_relay_url` keys off exactly that: with NIP-43 advertised and no `pairing_relay_url` present, it takes the `LegacyPath` branch and dials `wss:///pair`. The main relay has no such route, so pairing fails 100% of the time on a compose deployment:

```bash
curl -so /dev/null -w '%{http_code}\n' https://relay.example.com/pair
# 404
```

In the UI this renders as the QR code flashing on screen and immediately disappearing, with `WebSocket connection failed: HTTP error: 404 Not Found`.

**Suggested fix** — ship the sidecar in the compose bundle, the same way the chart does. A working local override, for reference:

```yaml
# compose.pair.yml
services:
pair-relay:
image: ${BUZZ_IMAGE}
entrypoint: ["/usr/local/bin/buzz-pair-relay"] # image ENTRYPOINT is buzz-relay, so `command:` is silently ignored
environment:
BUZZ_PAIR_RELAY_BIND_ADDR: 0.0.0.0:5000
restart: unless-stopped
networks: [buzz-net]
```

```caddyfile
{$BUZZ_DOMAIN} {
encode zstd gzip
@pair path /pair /pair/*
reverse_proxy @pair pair-relay:5000
reverse_proxy relay:3000
}
```

plus `BUZZ_PAIRING_RELAY_URL=wss:///pair` in `.env` so NIP-11 advertises it explicitly rather than relying on the legacy path convention. With that in place `/pair` returns `101 Switching Protocols` and pairing completes normally.

One footgun worth a comment in the example: because the image's `ENTRYPOINT` is `/usr/local/bin/buzz-relay`, using `command:` to select the pairing binary silently starts a **second main relay** instead. It then contends for the Postgres pool and crash-loops, and the proxy returns 502 — an error that looks nothing like the actual mistake.

---

Happy to open a PR for either or both if that's useful.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.