Relay Manager Docs

Architecture

Network topology, authentication layers, and Supabase as the state store.

Architecture

Network Topology

Production Deployments (BitMacro)

ComponentURLHosting
relay-panelhttps://relay-panel.bitmacro.ioVercel
relay-api (Web Server)https://relay-api.bitmacro.ioVercel
relay-connect-webSubdomain or pathVercel / self-hosted
relay-agent (Relay Server Agent)https://<operator-endpoint>Operator VPS / local hardware
SupabaseInternalSupabase Cloud

Network Requirements

  • The Relay Server Agent must be reachable by the Web Server (Vercel egress).
    If the agent runs on a LAN, expose it via tunnel: WireGuard + Nginx Proxy Manager, Cloudflare Tunnel, or ngrok.
  • relay-panel only needs access to relay-api. Zero direct access to agents or Supabase.
  • relay-connect-web proxies all /signer/* calls server-side — the browser never holds RELAY_API_KEY.

Connection Flow


Authentication Layers

Layer 1 — User Identity (relay-panel)

ProviderMechanism
GitHub OAuthNextAuth.js v5
Session IDproviderAccountId (numeric GitHub ID) stored as token.providerUserIdsession.user.id

session.user.id becomes X-Provider-User-Id on every server-side call to relay-api.

Layer 2 — Panel → Web Server

HeaderValueScope
X-API-Keyprocess.env.RELAY_API_KEYAll requests from panel
X-Provider-User-IdGitHub numeric IDFilters relay_configs rows by user

Alternative for clients with a NextAuth session: Authorization: Bearer <JWT> decoded via JWT_SECRET.

Layer 3 — Web Server → Relay Server Agent

  • v0.2 (multi-relay): Bearer token per relay instance, stored in RELAY_INSTANCES[].token and mirrored in relay_configs.token. Path prefix: /:relayId/.
  • v0.1 (legacy): Single RELAY_AGENT_TOKEN env var; no path prefix.
  • /healthno auth required on any version.

State Store (Supabase)

All persistent state lives in Supabase. The Relay Server Agent is completely stateless.

relay.relay_configs

ColumnTypeDescription
iduuidPK — gen_random_uuid()
nametextDisplay name
endpointtextAgent base URL
tokentextBearer token for agent
agent_relay_idtextLogical relay ID for multi-relay agent (v0.2)
provider_user_idtextGitHub user ID (NextAuth)
user_iduuidNullable, legacy

Index: idx_relay_configs_provider_user_id

relay.nip46_sessions

Sessions for NIP-46 pairing: links provider_user_id, relay_config_id, app pubkey, bridge_wss, pairing_secret, and status.

StatusMeaning
pendingURI generated, signer not yet paired
activePairing confirmed via POST /signer/session/:id/complete
revokedManually revoked

Migrations:

  • 20260324140000_relay_nip46_sessions.sql — table creation
  • 20260325130000_relay_nip46_sessions_grants.sql — PostgREST role grants (anon / authenticated / service_role); required to avoid 42501 on INSERT from relay-api

Request Trace: Panel → Stats


Environment Variables

relay-agent (Relay Server Agent)

VariableDescription
RELAY_AGENT_TOKEN(v0.1) Single Bearer token
RELAY_INSTANCES(v0.2) JSON array: [{id, token, strfryConfig, strfryDb, whitelistPath?}]
ALLOWED_ORIGINSCORS origins; default includes relay-panel.bitmacro.io

Example RELAY_INSTANCES:

[
  { "id": "public",  "token": "tok_pub",  "strfryConfig": "/etc/strfry-public.yml",  "strfryDb": "/var/lib/strfry/public.lmdb"  },
  { "id": "private", "token": "tok_priv", "strfryConfig": "/etc/strfry-private.yml", "strfryDb": "/var/lib/strfry/private.lmdb" },
  { "id": "paid",    "token": "tok_paid", "strfryConfig": "/etc/strfry-paid.yml",    "strfryDb": "/var/lib/strfry/paid.lmdb"   }
]

relay-api (Web Server)

VariableDescription
RELAY_API_KEYShared key with relay-panel and relay-connect-web
JWT_SECRETNextAuth JWT decode
SUPABASE_URLSupabase project URL
SUPABASE_SERVICE_ROLE_KEYFull access to relay schema

relay-panel

VariableDescription
NEXTAUTH_SECRETNextAuth secret
GITHUB_CLIENT_IDGitHub OAuth app
GITHUB_CLIENT_SECRETGitHub OAuth secret
NEXT_PUBLIC_API_URLWeb Server base URL
RELAY_API_URLServer-side override (avoids cold-start latency)
RELAY_API_KEYShared with relay-api

relay-connect-web

VariableDescription
RELAY_API_URLWeb Server base URL
RELAY_API_KEYShared key
SIGNER_PROVIDER_USER_IDGitHub ID for the operator account
NEXT_PUBLIC_RELAY_BRIDGE_WSSForce NIP-46 bridge wss://
NEXT_PUBLIC_NIP07_METADATA_RELAYSComma-separated relays for kind 0 after NIP-07
NEXT_PUBLIC_RELAY_CONFIG_IDPin a specific relay_configs UUID
SIGNER_PROXY_TIMEOUT_MSProxy timeout (ms)

CORS and security

SurfaceNotes
relay-agentCORS may allow https://relay-panel.bitmacro.io and http://localhost:3000 for testing; the panel does not call the agent directly in production.
relay-panelSession cookies on its own origin; all relay-api calls are server-side.
relay-apiPanel and connect proxies call from servers, not from arbitrary browser origins exposing secrets.

Secrets:

  • Never ship RELAY_API_KEY to the browser; relay-connect-web only attaches it on Next.js server routes.
  • Pairing for NIP-46 uses a per-session pairing_secret verified on POST /signer/session/:id/complete.

End-to-end docs map

AudienceWhere to start
Operators (terminal-free relay ops)Product landing and relay-panel
Full stack (marketing site → connect → API → agent)This docs section (/relay-manager/docs)
IntegratorsHTTP APIs, NIP-07, NIP-46