nostermd active
The home relay that complements Nosterm — a minimal NIP-29 managed-group Nostr relay in pure Go, with a Nosterm capability handshake and optional chat federation.
- role
- author & maintainer
- language
- Go (khatru)
- storage
- BoltDB (pure Go, no cgo)
- protocol
- NIP-01/11/42, NIP-29 groups
- image
- static binary on distroless
- status
- active
Overview
nostermd is the home relay that complements the Nosterm
client — a minimal NIP-29 managed-group Nostr relay built on
khatru
. It adds a Nosterm capability
handshake: a features array in its NIP-11 document so a Nosterm client can
feature-gate its UI and fall back gracefully on any plain relay.
Nostr is a client-side protocol — the browser talks directly to relays over WebSocket, so there is no shared backend. Nosterm runs a hybrid model: the client connects to public relays for general Nostr content while pointing at your own nostermd instance for private communities.
Why a separate repository
The client and the relay ship as two independent repositories and two independent images on purpose. Nothing binds them at runtime, so keeping them apart keeps the boundary honest:
- Mix and match — the client works against any relay; the relay serves any NIP-29 client. Neither depends on the other’s internals.
- Deploy each where it belongs — a static SPA and a stateful Go relay with a BoltDB store have different runtime, scaling, and persistence needs.
- Standards over coupling — forcing everything across the boundary to travel as plain Nostr events keeps the relay standards-first, never a Nosterm-only dialect.
What it does
- Serves NIP-01/11/42 via khatru, with pure-Go
BoltDB
storage — no cgo, so a fully static
binary that runs on
scratch/distroless. - Enforces a focused subset of NIP-29 managed groups: create/join/leave, admin put/remove user, member chat, and relay-signed group metadata.
- Advertises
software: "nostermd"and afeaturesarray in NIP-11 so clients can detect its capabilities. - Seeds a default channel on boot so a fresh relay is never empty — a client always has at least one open room to join.
- Optional federation — mirror or ingest chat with peer relays so a channel survives any single relay going down.
Architecture
Standard Go layout — a thin command over focused, independently-testable packages:
cmd/nostermd/ main: env config, key loading, khatru wiring, NIP-11 serving
internal/
group/ NIP-29 managed-group state machine (membership, admin, metadata)
federation/ optional chat mirroring/ingest with peer relays
retention/ background pruning of old chat messages
relayinfo/ Nosterm capability handshake (NIP-11 features array)Federation
Federation lets a channel live on more than one relay. It is off by default
and chat-only by design: only chat messages cross the relay boundary, while
membership, admins, bans, and metadata stay local to each relay — every operator
moderates their own instance. Loop prevention is structural: a re-received
event is a duplicate in the store, so the egress hook never fires twice and
A↔B↔A cycles die on the second sight. No “seen” set to tune or get wrong.
Principles
- Small footprint — a single pure-Go static binary, auditable, fast to start, cheap to self-host. No telemetry, no lock-in.
- Deploy anywhere — one runtime-configured image that drops onto overlay networks (Tor, I2P, Yggdrasil, Nym, and WireGuard-style meshes).
- Privacy by default — anonymity, encryption, and anti-censorship as the baseline behavior, not opt-in extras.