Skip to content

Letdown2491/torii

Repository files navigation

torii

A private, outbox-model nostr relay for you and a trusted group. Point your client at one relay and torii runs both directions of the outbox model on your behalf:

  • Feed in: ingests everyone you follow (from their NIP-65 write relays) into a local store: one complete, fresh, deduplicated feed, no per-follow fan-out.
  • Notes out: re-publishes your signed events to your own write relays and routes replies/mentions to the tagged recipients' read relays. Keyless: torii never holds your key.
  • Inbox: collects the replies and mentions addressed to you from your read relays, privately.
  • Archive: keeps your own events indefinitely (import your history; nothing of yours is auto-pruned) while everyone else's stays age-bounded.

Each member is an isolated tenant; nobody sees another's feed, inbox, or archive. Not a public relay: reads and writes are gated to a trusted set of npubs via NIP-42 AUTH, and torii never advertises itself or appears in your public relay list.

⚠️ Status: beta (0.x). torii is in daily use and has been through security, resilience, and performance audits, but it is still pre-1.0: expect occasional rough edges and breaking changes. Known limitation: events with content over 64 KB cannot be stored (a storage-codec bound). It is designed to run privately (bound to localhost and reached over Tailscale or a Tor hidden service). A public instance is supported but hardened, behind a TLS reverse proxy (see deploy/PUBLIC-DEPLOYMENT.md); exposing the relay port directly with no proxy is not. See SECURITY.md.

Stack

  • Go on fiatjaf.com/nostr
  • khatru relay framework (NIP-01 / NIP-11 / NIP-42)
  • LMDB event store (eventstore/lmdb), negentropy-capable
  • Thin, dependency-light; server-rendered dashboard (no npm)

Run with Docker (recommended)

Brings up torii plus a Tor sidecar that provides both an outbound SOCKS5 proxy and an inbound .onion hidden service, no manual Tor setup.

# create your config + env from the templates, then add your npub as a member:
cp config.docker.toml.example config.docker.toml   # then edit: add your npub
cp .env.example .env                                # optional: UID/GID, bind addr

docker compose up -d --build

# your relay's onion address (reachable over Tor):
docker compose exec tor cat /var/lib/tor/torii/hostname

# dashboard (localhost): http://127.0.0.1:3334/

(config.docker.toml and .env are gitignored, they're your live, editable config; the .example files are the checked-in templates.)

The dashboard and local clients reach it on 127.0.0.1:3334; anyone you trust reaches it over the .onion. Add its URL to your client (e.g. Satori), it's a plain nostr relay.

Run from source

go build ./cmd/torii
cp config.example.toml config.toml   # then edit (add your npub as a member)
./torii -config config.toml

Then open the dashboard at http://127.0.0.1:3334/ in a browser and sign in with your nostr extension (NIP-07) to configure and monitor the relay, and point your nostr client (e.g. Satori) at the same URL. If you leave owner blank, the first member to sign in becomes owner.

Check the NIP-11 document:

curl -s -H 'Accept: application/nostr+json' http://127.0.0.1:3334/ | jq

A bare-metal systemd unit is in deploy/torii.service. To run torii on a public address, follow deploy/PUBLIC-DEPLOYMENT.md (TLS proxy, private dashboard, per-IP limits). A future Start9 package fits naturally: StartOS provides Tor per service, and torii is already Tor-agnostic (configurable bind + SOCKS endpoint + /healthz), so the packaging is mostly a manifest.

Dashboard

Served at the relay URL in a browser (http://127.0.0.1:3334/); nostr clients get NIP-11 + websockets there, browsers get the dashboard. Sign in with your nostr key (NIP-07); the owner sees everything, other members get a view scoped to only their own data.

  • Overview: relay identity, addresses, and at-a-glance stats (yours, or the relay aggregate for the owner).
  • Notifications: replies, mentions, reactions and zaps collected for you (searchable, paged), filtered to your web of trust; remove items you don't want, or toggle the filter to see everything.
  • Archive: your event archive (searchable, paged) with per-event delivery status. Import your history here, and delete your own events (signed NIP-09, propagated to your write relays).
  • Sources (owner): the source-relay fleet, kind breakdown, and manual controls (backfill / reconcile / re-resolve / prune).
  • WoT: your web of trust. Review the accounts being filtered from your notifications, keep an allow/block list, and follow accounts your circle trusts.
  • Settings (owner, in the account menu): NIP-65 relay list, aggregation config, retention, Tor, and network access; most changes apply live (hot-reload).

Using torii with a client

torii is not a general public relay, and it behaves differently from one on purpose. Point a normal nostr client at it, but know what to expect:

  • Use it as your primary (ideally only) relay. torii serves a curated mirror of your world: your own events, your follows' events, and your inbox. Added as one relay among many, its scoped results merge confusingly with other relays' full results. It never lists itself in your NIP-65, so it stays your private back-end.
  • Your client must speak NIP-42. All reads require auth; a client that can't authenticate sees an empty relay (Damus, Amethyst, Primal, nostrudel, Coracle all handle it automatically).
  • A "global" / "explore" feed will be empty, and a stranger's profile you don't follow won't resolve. That's the design: torii mirrors your follow graph and inbox, not the whole network. Fetching a specific note or profile by id still works.
  • Notifications are filtered to your web of trust (people you follow plus their follows). A mention, reaction, or zap from a brand-new account outside that graph is held back; review and rescue it from the WoT tab in the dashboard, or toggle the filter off in Settings if you'd rather see everything. One exception: a direct reply to one of your own notes always comes through, even from outside your web of trust, so an answer to something you posted is never silently dropped. An account you have explicitly blocked stays blocked regardless.
  • Engagement (reactions, zaps) reflects your circle. torii aggregates your follows' reactions and zaps, so like/zap counts show your network's engagement, not the whole network's.

NIP compliance

torii is a relay, so it speaks the relay wire protocol strictly and stores everything else type-agnostically.

  • Serve to spec: NIP-01 (incl. replaceable/addressable keep-newest), NIP-11, NIP-42 (auth), NIP-09 (author-only deletes), NIP-40 (expiration), NIP-45 (count), NIP-70 (protected), NIP-77 (negentropy).
  • Consume for routing/discovery (not served/advertised): NIP-65 (relay lists), NIP-02 (follows), NIP-66 (relay-liveness monitors, used to find productive sources; torii never announces itself).
  • Admin: NIP-86 management API (owner-only HTTP control plane).
  • Store type-agnostically: every content kind (notes, comments, articles, pictures, videos, highlights, wiki, calendar, code, lists, zaps, …).
  • Deliberately not: announcing via NIP-66; public/open writes.

Advertised set: supported_nips = [1, 9, 11, 40, 42, 45, 70, 77, 86].

Build plan

Phase Delivers
0 Scaffold, config, khatru + LMDB serving NIP-11 · done ✓
1 NIP-42 AUTH + trusted-group allowlist · done ✓
2 Follow-graph resolver + relay-grouped live ingestion + replace-aware dedup · done ✓
3 Backfill (until-cursor) + kind-tiered retention/GC · done ✓
4 Relay profiler + seen-relays + operational dashboard · done ✓
5 Negentropy (NIP-77): serve to clients + gap-fill from sources · done ✓
6 Docker + Tor sidecar (in/out) + write-mirror + healthz/ops · done ✓
7 Dashboard redesign + live data/sparkline + controls + settings · done ✓
7b NIP-86 management API + settings hot-reload · done ✓
8 Outbox proxy, re-publish your signed notes to your NIP-65 write relays + route replies to the recipients' inbox relays · done ✓
9 Inbox aggregation, collect your mentions from your read relays (private, backfilled) · done ✓
10 Per-member read isolation, each member an isolated tenant (feed / inbox / archive) · done ✓
11 Personal archive, member events kept indefinitely + on-demand history import · done ✓
12 Delete, signed NIP-09 for your own events + local inbox remove · done ✓
13 NIP-17/59 encrypted DM zone, blind transport (collect + route gift wraps), kind:10050 management, DM history import · done ✓
14 Web-of-Trust inbox filter (degree≤2), on by default, with a WoT dashboard tab (filtered-account review, allow/block, circle follow suggestions) · done ✓
(deferred) NIP-67 completeness hints (blocked upstream in khatru); NIP-50 full-text search; NIP-66 source discovery

Contributing & license

Contributions welcome, see CONTRIBUTING.md for build/test/PR guidance, and SECURITY.md to report a vulnerability privately.

Licensed under the MIT License.

About

Torii is a private outbox aggregator relay with build in inbound and outbound Tor support.

Topics

Resources

License

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages