Files
smirk-backend-core/deploy/relay/docker-compose.yml
jwinterm 635cb64601 fix(relay): harden admission (fail-safe, loopback-only, bounded, size cap) [review]
Adversarial review of the relay admission surface:

- FAIL-SAFE on admission death: nostr-rs-relay fails OPEN if its gRPC admission
  server is unreachable, so a dead admission = an unrestricted relay. The backend
  now EXITS if the admission service stops (supervisor restarts a clean pair);
  documented in RELAY.md. Pin the relay image to a digest (compose note).
- Registration-oracle protection: validate() now refuses a non-loopback
  RELAY_ADMISSION_BIND unless RELAY_ADMISSION_ALLOW_PUBLIC=true (+ test).
- No N+1 on crafted events: recipient p-tags are capped (20, deduped) and resolved
  in ONE batched query (db.any_registered_npub) instead of one-per-tag.
- Defence-in-depth size cap: admission denies events over max_event_bytes before
  any DB work (the relay enforces its own limit too).
- Docs: RELAY.md Security section (fail-open, loopback oracle, default PoW=0 spam
  footgun, client sender-verification); config.toml relay port 8088 (not 8080);
  Docker Hub image; .env.example RELAY_ADMISSION_ALLOW_PUBLIC.

Note: the client-side sender-impersonation blocker is fixed separately in the
monorepo (verifying gift-wrap unwrap).
2026-07-02 08:35:37 -04:00

38 lines
1.6 KiB
YAML

# Bundled, locked-down Nostr relay for a self-hosted Smirk backend.
#
# This runs nostr-rs-relay as the messaging-plane relay. WRITE ADMISSION is
# delegated to the Smirk backend's gRPC service (RELAY_ADMISSION_BIND, default
# 127.0.0.1:8090) via nostr-rs-relay's [grpc] event_admission_server hook — so
# the RELAY_WRITE_POLICY (inbox-outbox / author-allowlist / open) + NIP-13 PoW
# are enforced by the backend, not baked into this file.
#
# Networking: the relay uses the HOST network so it can reach the backend's
# loopback admission socket (127.0.0.1:8090) while keeping that socket private.
# host networking is Linux-only; on other hosts, bind RELAY_ADMISSION_BIND to a
# docker-reachable address behind your firewall and drop `network_mode: host`,
# adding `extra_hosts: ["host.docker.internal:host-gateway"]` + a port mapping.
#
# This is a REFERENCE template — verify the config keys against the nostr-rs-relay
# version you pin (https://github.com/scsibug/nostr-rs-relay).
services:
relay:
# SECURITY: pin a digest in production — the relay's admission fail-open
# behavior can change across versions (see docs/operations/RELAY.md).
image: scsibug/nostr-rs-relay:latest
restart: unless-stopped
network_mode: host # reach the backend admission socket on 127.0.0.1
user: "1000:1000"
volumes:
- ./config.toml:/usr/src/app/config.toml:ro
- relay-data:/usr/src/app/db
environment:
RUST_LOG: info
# Modest, self-host-friendly resource ceilings.
deploy:
resources:
limits:
memory: 512M
volumes:
relay-data: