Summary
In frontend/components/ui/relay-input.tsx, a useEffect hook auto-inserts wss://relay.primal.net whenever the relay list is empty. This makes it impossible to replace the single pre-populated primal relay with a different one through the UI — deleting it just triggers the effect and re-adds it.
Offending code
https://github.com/FROSTR-ORG/igloo-server/blob/main/frontend/components/ui/relay-input.tsx#L87-L92
// Add a default relay if the list is empty
useEffect(() => {
if (relays.length === 0) {
const defaultRelay = "wss://relay.primal.net";
onChangeRef.current([defaultRelay]);
}
}, [relays.length]);
Reproduce
- Fresh onboarding in Database mode. The Configure tab shows one relay:
wss://relay.primal.net.
- Click the trash icon next to it.
- The relay list momentarily empties, then the effect fires and re-inserts
wss://relay.primal.net.
- Alternative workflow: add your own relay first so the list has two entries, then delete primal. This also fails under certain persistence paths — once the list is saved and reloaded, primal reappears at the top on next visit (likely because the config round-trip goes through a path that empties the list transiently and the effect refills it).
Net effect: you can never end up with a relay list that does not contain wss://relay.primal.net.
Impact
- Users who run their own relay (e.g., for a self-hosted test deployment, privacy, or network isolation) cannot point the signer exclusively at their relay via the UI. The signer ends up publishing/subscribing on primal regardless.
- In a FROSTR test setup using a dedicated private relay, the signer connects to primal, NIP-07 extensions (e.g., Frost2x) broadcast signing requests on the intended relay, and signing silently fails because signer ↔ client have no relay in common.
Workaround (users)
Set RELAYS in the env — it seeds the list with your own relay and is not overwritten by the effect:
RELAYS=[\"wss://my-own-relay.example.org\"]
This works around the symptom but the UI remains broken: users can still not edit the relay list via Configure without primal reappearing.
Suggested fix
Either:
- Drop the effect entirely. An empty relay list is a valid state — the backend/UI can show a warning ("no relays configured") rather than silently re-injecting a third-party default. This is the least surprising behavior and respects user intent.
- Only seed when the component mounts with no relays AND nothing is saved server-side (e.g., first-time onboarding, before the user has touched Configure). After the user has explicitly cleared the list, do not re-add. The cleanest way is to seed at the API / initial-load layer, not in a render-time effect in the input component.
- At minimum, don't hardcode a third-party relay. If a default is desired, make it configurable via env (e.g.,
DEFAULT_RELAY) with a sane fallback, so operators of self-hosted/private deployments aren't forced onto relay.primal.net.
Happy to open a PR if a direction is preferred.
Environment
- Version:
ghcr.io/frostr-org/igloo-server:1.1.0
- Mode: Database (UI onboarding)
- Discovered while standing up a private FROSTR test relay and wiring an always-on signer at it via an Ansible role.
Summary
In
frontend/components/ui/relay-input.tsx, auseEffecthook auto-insertswss://relay.primal.netwhenever the relay list is empty. This makes it impossible to replace the single pre-populated primal relay with a different one through the UI — deleting it just triggers the effect and re-adds it.Offending code
https://github.com/FROSTR-ORG/igloo-server/blob/main/frontend/components/ui/relay-input.tsx#L87-L92
Reproduce
wss://relay.primal.net.wss://relay.primal.net.Net effect: you can never end up with a relay list that does not contain
wss://relay.primal.net.Impact
Workaround (users)
Set
RELAYSin the env — it seeds the list with your own relay and is not overwritten by the effect:This works around the symptom but the UI remains broken: users can still not edit the relay list via Configure without primal reappearing.
Suggested fix
Either:
DEFAULT_RELAY) with a sane fallback, so operators of self-hosted/private deployments aren't forced ontorelay.primal.net.Happy to open a PR if a direction is preferred.
Environment
ghcr.io/frostr-org/igloo-server:1.1.0