# Example config for geode. Section layout mirrors # nostr-rs-relay's config.toml so existing operators can port across. # # Run with: # ./gradlew :geode:run --args="--config /etc/geode.toml" # # CLI flags override individual values: e.g. `--port 8888` wins over # `[network].port`. [info] # The wss:// URL clients use to reach this relay (mandatory for NIP-42 # AUTH challenges). If not set, the relay synthesises one from the # [network] section. relay_url = "wss://relay.example.com/" name = "Example Geode" description = "A geode deployment." contact = "admin@example.com" # Operator pubkey (NIP-11). Optional. # pubkey = "..." # Override the supported NIPs advertised on the NIP-11 endpoint. If # omitted, the relay advertises the NIPs it actually implements. # supported_nips = [1, 9, 11, 40, 42, 45, 50, 62] [network] host = "0.0.0.0" port = 7447 path = "/" # Ktor CIO event-loop pool sizing. Leave commented-out for sensible # per-CPU defaults (typical for <2k concurrent connections). Lift on # big-VM deployments targeting 10k+ connections — over-threading at # low connection counts hurts L1/L2 cache locality, so always # benchmark before/after when tuning these. # # Operators targeting >1k concurrent WebSockets should also raise the # OS file-descriptor limit: `ulimit -n 65536` (or higher) before # launching, plus a matching `LimitNOFILE=` in any systemd unit. The # default of 1024 on most distros caps the relay well below 1k FDs # (one per WS plus DB and listening sockets). # connection_group_size = 4 # worker_group_size = 16 # call_group_size = 64 [database] # True keeps an in-memory SQLite db (events vanish on restart). Useful # for tests; set false + `file = "..."` for persistent storage. in_memory = false file = "/var/lib/geode/events.db" [options] # Drop events whose Schnorr signature does not verify. Strongly # recommended for any relay accepting traffic from real clients. # Verify Schnorr signatures on every EVENT. Default: true. Disable # only for trusted-input scenarios (test fixtures, mirror replays). verify_signatures = true # Run signature verification in parallel inside the IngestQueue # (across all CPU cores) instead of serially on each connection's # WebSocket pump. Default: true. Set false to fall back to the # legacy in-policy verify path. # parallel_verify = true # Require clients to NIP-42 AUTH before REQ/EVENT/COUNT. require_auth = false # Reject events whose `created_at` is more than this many seconds in # the future. Enforced by RejectFutureEventsPolicy. # reject_future_seconds = 1800 [authorization] # Allow / deny lists. Allow is a permissive ceiling; deny still # removes specific entries inside it. Enforced by Pubkey/KindAllowDenyPolicy. # pubkey_whitelist = ["abcdef...64hex..."] # pubkey_blacklist = [] # kind_whitelist = [0, 1, 3, 7, 1059, 30023] # kind_blacklist = [4] [admin] # NIP-86 relay management API. When `pubkeys` is non-empty, the relay # accepts HTTP POST application/nostr+json+rpc on the same URL, # authenticated with NIP-98 HTTP-Auth. Only events signed by one of # the listed pubkeys can run admin RPCs (banpubkey / banevent / # changerelayname / …). Empty (the default) disables the endpoint. # # NIP-98 binds admin tokens to the relay's HTTP URL, which is derived # from [info].relay_url with the scheme swapped (ws -> http, wss -> # https) per NIP-86. Make sure [info].relay_url is set to the # canonical public URL when behind TLS termination or a reverse proxy. # pubkeys = ["abcdef...64hex..."] # Path for the JSON snapshot that persists NIP-86 admin state (ban # lists + the live NIP-11 doc) across restarts. When unset, admin # state is in-memory only and forgotten on every restart. Convention # is to place this next to the SQLite event-store file. # state_file = "/var/lib/geode/events.db.admin.json"