Relay Server Agent
Stateless REST abstraction over strfry. MIT, self-hosted, operator-owned.
Relay Server Agent (relay-agent)
License: MIT — github.com/bitmacro/relay-agent
Distribution: npx @bitmacro/relay-agent or docker pull ghcr.io/bitmacro/relay-agent:0.2.0
Port: 7810
State: None — all state lives in Supabase via the Web Server.
Runs on the same server as the relay process. Exposes an authenticated REST API that wraps strfry CLI commands. One container, N relays.
Deployment
Docker Compose (recommended)
# infra/compose/relay-agent.yml
services:
relay-agent:
image: ghcr.io/bitmacro/relay-agent:0.2.0
ports:
- "7810:7810"
environment:
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"}
]
ALLOWED_ORIGINS: "https://relay-panel.bitmacro.io"
volumes:
- /etc/strfry:/etc/strfry:ro
- /var/lib/strfry:/var/lib/strfry
restart: unless-stoppednpx (development / quick test)
RELAY_INSTANCES='[{"id":"local","token":"dev","strfryConfig":"/etc/strfry.yml","strfryDb":"/var/lib/strfry/db"}]' \
npx @bitmacro/relay-agentAPI Reference (v0.2.0 — multi-relay)
All routes except /health and /:relayId/health require Authorization: Bearer <token>.
relayId matches the id field in RELAY_INSTANCES.
Global
| Method | Route | Auth | Response |
|---|---|---|---|
| GET | /health | — | {status:"ok", relayIds:["public","private","paid"], version:"0.2.0"} |
Per-relay (/:relayId/)
| Method | Route | Description |
|---|---|---|
| GET | /:relayId/health | Health for specific relay |
| GET | /:relayId/stats | {total_events, db_size_bytes, uptime_seconds, strfry_version} |
| GET | /:relayId/events | Query events (NIP-01 filters via query params) |
| DELETE | /:relayId/events/:id | Delete event by ID |
| GET | /:relayId/policy | Write policy (whitelist); strips comments and invalid pubkeys |
| POST | /:relayId/policy/allow | Add pubkey to whitelist |
| POST | /:relayId/policy/block | Add pubkey to blocklist + delete all their events |
| GET | /:relayId/users | Unique pubkeys from kinds 0, 1, 3 |
v0.1 compatibility
When RELAY_INSTANCES is not set, the agent falls back to v0.1 mode: single relay, single RELAY_AGENT_TOKEN, no path prefix.
Multi-Relay Internals
- One LMDB mutex per
relayId— reduces503 Resource temporarily unavailableon concurrent strfry access. strfryConfigandstrfryDbare per-instance, allowing fully isolated relay DBs on the same host.- The agent process spawns strfry commands via:
This avoids TTY/EACCES issues on Ubuntu 24 kernel restriction.spawn('/bin/sh', ['-c', cmd], { stdio: ['ignore', 'pipe', 'pipe'] })
CI/CD
| Trigger | Action |
|---|---|
Push tag v*.*.* | publish.yml → npm publish + GHCR multi-arch (amd64 + arm64) |
PR to main | ci.yml → Vitest (unit + integration; strfry-dependent tests skip if not present) |
OIDC provenance (id-token: write) bypasses 2FA on CI publish.
Monitoring
Uptime Kuma: HTTP(s) keyword check on https://relay-agent.bitmacro.io/health
Keyword: "status":"ok"