Operate / CONFIGURATION.md

Configuration

Environment variables

The following environment variables can be set:

NameDescriptionDefault
SECRETLong random secret.changeme
RELAY_PORTRelay’s server port8008
RELAY_PRIVATE_KEYRelay’s private key in hex(auto-generated)
WORKER_COUNTNumber of workers overrideNo. of available CPUs
DB_URIPostgreSQL URI (overrides DB_HOST, DB_PORT, etc.)
DB_HOSTPostgresSQL Hostname
DB_PORTPostgreSQL Port5432
DB_USERPostgreSQL Usernamenostr_ts_relay
DB_PASSWORDPostgreSQL Passwordnostr_ts_relay
DB_NAMEPostgreSQL Database namenostr_ts_relay
DB_MIN_POOL_SIZEMin. connections per worker0
DB_MAX_POOL_SIZEMax. connections per worker3
DB_ACQUIRE_CONNECTION_TIMEOUTNew connection timeout (ms)60000
READ_REPLICA_ENABLEDRead Replica (RR) Toggle‘false’
READ_REPLICASNumber of read replicas (RR0, RR1, …, RRn)2
RR0_DB_HOSTPostgresSQL Hostname (RR)
RR0_DB_PORTPostgreSQL Port (RR)5432
RR0_DB_USERPostgreSQL Username (RR)nostr_ts_relay
RR0_DB_PASSWORDPostgreSQL Password (RR)nostr_ts_relay
RR0_DB_NAMEPostgreSQL Database name (RR)nostr_ts_relay
RR0_DB_MIN_POOL_SIZEMin. connections per worker (RR)0
RR0_DB_MAX_POOL_SIZEMax. connections per worker (RR)3
RR0_DB_ACQUIRE_CONNECTION_TIMEOUTNew connection timeout (ms) (RR)60000
RR1_DB_HOSTPostgresSQL Hostname (RR)
RR1_DB_PORTPostgreSQL Port (RR)5432
RR1_DB_USERPostgreSQL Username (RR)nostr_ts_relay
RR1_DB_PASSWORDPostgreSQL Password (RR)nostr_ts_relay
RR1_DB_NAMEPostgreSQL Database name (RR)nostr_ts_relay
RR1_DB_MIN_POOL_SIZEMin. connections per worker (RR)0
RR1_DB_MAX_POOL_SIZEMax. connections per worker (RR)3
RR1_DB_ACQUIRE_CONNECTION_TIMEOUTNew connection timeout (ms) (RR)60000
RRn_DB_HOSTPostgresSQL Hostname (RR)
RRn_DB_PORTPostgreSQL Port (RR)5432
RRn_DB_USERPostgreSQL Username (RR)nostr_ts_relay
RRn_DB_PASSWORDPostgreSQL Password (RR)nostr_ts_relay
RRn_DB_NAMEPostgreSQL Database name (RR)nostr_ts_relay
RRn_DB_MIN_POOL_SIZEMin. connections per worker (RR)0
RRn_DB_MAX_POOL_SIZEMax. connections per worker (RR)3
RRn_DB_ACQUIRE_CONNECTION_TIMEOUTNew connection timeout (ms) (RR)60000
TOR_HOSTTor Hostname
TOR_CONTROL_PORTTor control Port9051
TOR_PASSWORDTor control passwordnostr_ts_relay
HIDDEN_SERVICE_PORTTor hidden service port80
REDIS_URIRedis URI (overrides REDIS_HOST, REDIS_PORT, etc.)
REDIS_HOST
REDIS_PORTRedis Port6379
REDIS_USERRedis Userdefault
REDIS_PASSWORDRedis Passwordnostr_ts_relay
RELAY_BROADCAST_FANOUTPublish accepted events to a Redis stream so multiple relay containers share live fan-out (true/false)false
RELAY_BROADCAST_STREAM_KEYRedis stream key used when RELAY_BROADCAST_FANOUT is enablednostream:relay:broadcast
RELAY_BROADCAST_STREAM_MAXLENApproximate max entries retained on the broadcast Redis stream (XADD trim). Dominant Redis memory use when fan-out is enabled.50000
RELAY_INSTANCE_IDOptional stable id for this relay instance (defaults to hostname and pid)
PROMETHEUS_URLPrometheus base URL for admin metrics querieshttp://127.0.0.1:9090
PROMETHEUS_QUERY_TIMEOUT_MSTimeout for each Prometheus admin metrics query (ms)5000
ADMIN_METRICS_SSE_INTERVAL_MSInterval between /admin/metrics SSE snapshots (ms)5000
ADMIN_METRICS_SNAPSHOT_TIMEOUT_MSTimeout for collecting one /admin/metrics snapshot (ms)10000
ADMIN_DEPENDENCY_PING_TIMEOUT_MSTimeout for admin DB/Redis dependency pings (ms)3000
GRAFANA_URLGrafana base URL for admin dashboard embedshttp://127.0.0.1:7777
NOSTR_CONFIG_DIRConfiguration directory<project_root>/.nostr/
MONITOR_PRIVATE_KEYHex-encoded private key for the NIP-66 monitor identity that will sign kind 30166/10166 events. Configure via environment variable, not settings.yaml.
DEBUGDebugging filter
ZEBEDEE_API_KEYZebedee Project API Key
NWC_URLNWC connection URL (nostr+walletconnect://...)

I2P

I2P support is provided as a sidecar container (i2pd) via docker-compose.i2p.yml, mirroring the Tor setup. No application-level environment variables are needed — the i2pd container creates an I2P server tunnel that forwards traffic to nostream’s WebSocket port.

Configuration files live in the i2p/ directory:

FileDescription
i2p/tunnels.confDefines the I2P server tunnel pointing at nostream (port 8008).
i2p/i2pd.confMinimal i2pd daemon configuration.

Tunnel keys are persisted at .nostr/i2p/data/ so the .b32.i2p address survives container restarts.

The i2pd web console (tunnel status, .b32.i2p destinations) is published to the host on 127.0.0.1:7070 only. Remove the ports: mapping in docker-compose.i2p.yml to disable host-side access.

  • Start with I2P: nostream start --i2p

If you’ve set READ_REPLICAS to 4, you should configure RR0_ through RR3_.

Database indexes and benchmarking

The schema ships with a small, query-driven set of indexes. The most important ones for relay hot paths are:

IndexCovers
events_active_pubkey_kind_created_at_idxREQ with authors+kinds ordered by created_at DESC, event_id ASC; hasActiveRequestToVanish; by-pubkey deletes. Composite key (event_pubkey, event_kind, event_created_at DESC, event_id) so the ORDER BY tie-breaker is satisfied from the index without a sort step.
events_deleted_at_partial_idxRetention purge over soft-deleted rows. Partial on deleted_at IS NOT NULL.
invoices_pending_created_at_idxfindPendingInvoices poll (ORDER BY created_at ASC). Partial on status = 'pending'.
event_tags (tag_name, tag_value)NIP-01 generic tag filters (#e, #p, #K, #I, …) via the normalized event_tags table. Both lowercase and uppercase single-letter tag filters are supported.
events_event_created_at_indexTime-range scans (since / until).
events_event_kind_indexKind-only filters and purge kind-whitelist logic.

Run the read-only benchmark against your own database to confirm the planner is using the expected indexes and to record baseline latencies:

pnpm db:benchmark
pnpm db:benchmark --runs 5 --kind 1 --limit 500

The db:benchmark script loads the local .env file automatically (via node --env-file-if-exists=.env), using the same DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME variables as the relay. The benchmark issues only EXPLAIN (ANALYZE, BUFFERS) and SELECT statements — it never writes. Flags: --runs <n> (default 3), --kind <n> (default 1 / TEXT_NOTE; pass 0 for SET_METADATA), --limit <n> (default 500), --horizon-days <n> (default 7), --help.

For a full before/after proof of the index impact (seeds a throwaway dataset, drops and recreates the indexes, and prints a BEFORE/AFTER table), use:

pnpm db:verify-index-impact

The hot-path index migration (20260420_120000_add_hot_path_indexes.js) uses CREATE INDEX CONCURRENTLY, so it can be applied to a running relay without taking ACCESS EXCLUSIVE locks on the events or invoices tables.

Tag filter scope

Subscription filters support single-letter tag filters using the #<letter> key syntax (NIP-01). Both lowercase (#a–#z) and uppercase (#A–#Z) variants are accepted.

ScopeExamplesUsage
Lowercase (#a–#z)#e, #p, #a, #kStandard NIP-01 tag queries; parent-level references in NIP-22 comment threading
Uppercase (#A–#Z)#E, #P, #A, #K, #IRoot-level references in NIP-22 comment threading and other NIPs that use uppercase to distinguish root vs. parent scope

NIP-22 comment threading (kind 1111): NIP-22 comment events use lowercase tags (#e, #a, #i, #k) to reference the immediate parent and uppercase tags (#E, #A, #I, #K) to reference the root item. Filters must therefore accept both cases to allow clients to query the full comment thread hierarchy. For example, to find all comments on a root event: {"kinds":[1111],"#E":["<root-event-id>"]}, or to find comments of a specific root kind: {"kinds":[1111],"#K":["1"]}.

Settings

Running nostream for the first time creates the settings file in <project_root>/.nostr/settings.yaml. If the file is not created and an error is thrown ensure that the <project_root>/.nostr folder exists. The configuration directory can be changed by setting the NOSTR_CONFIG_DIR environment variable. nostream will pick up any changes to this settings file without needing to restart.

The settings below are listed in alphabetical order by name. Please keep this table sorted when adding new entries.

NameDescription
admin.nip98.allowedPubkeysHex pubkeys allowed to use NIP-98 on the admin API. Empty means nobody (fail-closed). Defaults to [].
admin.nip98.enabledAccept Authorization: Nostr (NIP-98) on protected admin API routes alongside session auth. Defaults to false. Clients must sign u using the HTTP(S) scheme and host derived from info.relay_url (ws/http → http, wss/https → https; never the request Host), plus the public path prefix and /admin/.... Successful auth events are one-time through created_at + maxSkewSeconds (Redis).
admin.nip98.maxSkewSecondsMax skew in seconds between now and the auth event created_at. Replay claims last until that window ends (inclusive). Defaults to 60.
dvm.workers[].argsArguments passed to the spawned command. Optional.
dvm.workers[].commandCommand to spawn for this DVM worker (e.g. an interpreter or executable path).
dvm.workers[].kindsNIP-90 job request kinds (5000-5999) this worker accepts. Optional.
dvm.workers[].timeoutMsMax time in ms to wait for a job result before considering it timed out. Optional.
eventStore.backendWhere events are stored. Only postgres for now. Read once at startup, so changing it needs a restart; an unsupported value stops the relay. Defaults to postgres.
info.bannerPublic banner image URL for the relay information document.
info.contactRelay operator’s contact. (e.g. mailto:operator@relay-your-domain.com)
info.descriptionPublic description of your relay. (e.g. Toronto Bitcoin Group Public Relay)
info.iconPublic icon image URL for the relay information document.
info.namePublic name of your relay. (e.g. TBG’s Public Relay)
info.pubkeyRelay operator’s Nostr pubkey in hex format.
info.relay_urlPublic-facing URL of your relay. (e.g. wss://relay.your-domain.com)
info.selfOptional. The relay’s own signing pubkey (hex or npub1...), published as self in the relay information document. NIP-43 clients verify relay-signed events against it, so it must match the key the relay signs with. Leave unset to derive it from SECRET; run nostream info to print the derived value. A configured value that does not match disables kind 28935 invite requests.
info.terms_of_servicePublic URL to relay terms of service.
limits.admissionCheck.ipWhitelistList of IPs (IPv4 or IPv6) to ignore rate limits.
limits.admissionCheck.rateLimits[].periodRate limit period in milliseconds.
limits.admissionCheck.rateLimits[].rateMaximum number of admission checks during period.
limits.client.subscription.maxFiltersMaximum number of filters per subscription. Defaults to 10. Disabled when set to zero.
limits.client.subscription.maxFilterValuesMaximum number of values allowed in each filter, counting its array criteria (ids, authors, kinds, #<tag>) together. Defaults to 2500. Disabled when set to zero.
limits.client.subscription.maxSubscriptionsMaximum number of subscriptions per connected client. Defaults to 10. Disabled when set to zero.
limits.event.content[].kindsList of event kinds to apply limit. Use [min, max] for ranges. Optional.
limits.event.content[].maxLengthMaximum length of content. Defaults to 1 MB. Disabled when set to zero.
limits.event.createdAt.maxNegativeDeltaMaximum number of seconds an event’s created_at can be in the past. Defaults to zero. Disabled when set to zero.
limits.event.createdAt.maxPositiveDeltaMaximum number of seconds an event’s created_at can be in the future. Defaults to 900 (15 minutes). Disabled when set to zero.
limits.event.eventId.minLeadingZeroBitsLeading zero bits required on every incoming event for proof of work. Defaults to zero. Disabled when set to zero. Ignored on the client path while limits.event.pow.enabled is true (mirrored events from static-mirroring-worker.ts still enforce this static value).
limits.event.kind.blacklistList of event kinds to always reject. Leave empty to allow any.
limits.event.kind.whitelistList of event kinds to always allow. Leave empty to allow any.
limits.event.pow.ceilingBitsMaximum adaptive PoW difficulty, reached at approximately 2x targetEventsPerSecond and beyond.
limits.event.pow.enabledEnables load-aware PoW difficulty scaling on the eventId check only, in place of the static eventId.minLeadingZeroBits value. Does not affect pubkey.minLeadingZeroBits, which stays a static, non-adaptive knob regardless of this setting — a pubkey requirement is a one-time offline identity cost, not a per-event load signal. Defaults to false.
limits.event.pow.floorBitsMinimum adaptive PoW difficulty, used at or below approximately targetEventsPerSecond. With the default floorBits: 0, the load signal costs an attacker nothing to drive; set a non-zero floor if the gate should cost something even under light load.
limits.event.pow.periodMsEWMA half-life (ms) used to smooth the observed event rate.
limits.event.pow.targetEventsPerSecondEvent-rate threshold (in real events/sec) above which the adaptive difficulty starts climbing toward ceilingBits.
limits.event.pow.wotThresholds[].difficultyFactorFraction of the computed adaptive difficulty required at this threshold’s maxDistance: 0 bypasses eventId PoW entirely, 1 requires the full computed difficulty.
limits.event.pow.wotThresholds[].maxDistanceReporters at or under this WoT distance (from wot.seedPubkey) get this threshold’s difficultyFactor. The eligible threshold with the smallest maxDistance applies. Requires wot.enabled; a pubkey outside the trust graph always pays the full computed difficulty.
limits.event.pubkey.blacklistList of public keys to always reject. Public keys in this list will not be able to post to this relay.
limits.event.pubkey.minLeadingZeroBitsLeading zero bits required on the public key of incoming events for proof of work. Defaults to zero. Disabled when set to zero. Always enforced regardless of limits.event.pow.enabled — adaptive PoW never applies to the pubkey check (see limits.event.pow.enabled).
limits.event.pubkey.whitelistList of public keys to always allow. Only public keys in this list will be able to post to this relay. Use for private relays.
limits.event.rateLimits[].kindsList of event kinds rate limited. Use [min, max] for ranges. Optional.
limits.event.rateLimits[].periodRate limiting period in milliseconds. For sliding_window: the time window during which requests are counted. For ewma: the half-life of the exponential decay — shorter values forget bursts faster, longer values are stricter on bursty clients.
limits.event.rateLimits[].rateMaximum number of events during period.
limits.event.retention.kind.whitelistEvent kinds excluded from retention purge. NIP-62 REQUEST_TO_VANISH is always excluded from retention purge, even if not listed here.
limits.event.retention.maxDaysMaximum number of days to retain events. Purge deletes events that are expired (expires_at), soft-deleted (deleted_at), or older than this window (created_at). Any non-positive value disables retention purge.
limits.event.retention.pubkey.whitelistPublic keys excluded from retention purge.
limits.event.whitelists.ipAddressesList of IPs (IPv4 or IPv6) to ignore rate limits.
limits.event.whitelists.pubkeysList of public keys to ignore rate limits.
limits.invite.rateLimits[].periodRate limit period in milliseconds for NIP-43 kind 28935 invite requests, counted per requesting pubkey.
limits.invite.rateLimits[].rateMaximum number of invite requests a single pubkey may make during period. Each granted request writes a row to invite_codes, so this is the main defence against a code flood. Defaults to 5 per hour.
limits.message.ipWhitelistList of IPs (IPv4 or IPv6) to ignore rate limits.
limits.message.rateLimits[].periodRate limit period in milliseconds.
limits.client.subscription.maxSubscriptionsMaximum number of subscriptions per connected client. Defaults to 10. Disabled when set to zero.
limits.client.subscription.maxFiltersMaximum number of filters per subscription. Defaults to 10. Disabled when set to zero.
limits.message.rateLimits[].periodRate limiting period in milliseconds. For sliding_window: the time window. For ewma: the half-life of the decay function.
limits.message.rateLimits[].rateMaximum number of messages during period.
mirroring.static[].addressAddress of mirrored relay. (e.g. ws://100.100.100.100:8008)
mirroring.static[].filtersSubscription filters used to mirror.
mirroring.static[].limits.eventEvent limit overrides for this mirror. See configurations under limits.event.
mirroring.static[].secretSecret to pass to relays. Nostream relays only. Optional.
mirroring.static[].skipAdmissionCheckDisable the admission fee check for events coming from this mirror.
network.maxPayloadSizeMaximum number of bytes accepted per WebSocket frame
network.remoteIpHeaderHTTP header from proxy containing IP address from client.
nip05.domainBlacklistList of domains blocked from NIP-05 verification. Authors with NIP-05 at these domains will be rejected.
nip05.domainWhitelistList of domains allowed for NIP-05 verification. If set, only authors verified at these domains can publish.
nip05.maxConsecutiveFailuresNumber of consecutive verification failures before giving up on an author. Defaults to 20.
nip05.modeNIP-05 verification mode: enabled requires verification, passive verifies without blocking, disabled does nothing. Defaults to disabled.
nip05.verifyExpirationTime in milliseconds before a successful NIP-05 verification expires and needs re-checking. Defaults to 604800000 (1 week).
nip05.verifyUpdateFrequencyMinimum interval in milliseconds between re-verification attempts for a given author. Defaults to 86400000 (24 hours).
nip42.authRequiredWhen true, clients must NIP-42 AUTH as the event author before publishing events. Advertised in NIP-11 as limitation.restricted_writes (not auth_required, which means AUTH before any connection action). Defaults to false.
nip42.sessionExpirySecondsSeconds after which an authenticated pubkey must AUTH again on the same WebSocket. 0 (default) keeps the session for the connection lifetime.
nip42.restrictedReads.enabledEnable NIP-42 auth-based read filtering. When enabled, events of the restricted kinds are only delivered to clients that have authenticated as the event’s author or as a pubkey listed in the event’s p tags. Applies to stored events (REQ), live broadcasts and COUNT queries. Subscriptions that exclusively target restricted kinds from unauthenticated clients are closed with an auth-required: reason. Defaults to false.
nip42.restrictedReads.kindsList of event kinds (or [min, max] ranges) protected by auth-based read filtering. Defaults to [4, 1059] (NIP-04 encrypted direct messages and NIP-59 gift wraps).
nip43.enabledEnable NIP-43 invite-based membership. When true, only admitted members may publish. Defaults to false.
nip43.inviteCodeExpirySecondsSeconds until a newly minted invite code expires. 0 means the code never expires. Defaults to 600 (10 minutes).
nip43.defaultMaxUsesHow many times a newly minted invite code can be claimed. Defaults to 1.
nip43.allowInviteRequestsAnswer REQs for kind 28935 by minting an invite code on the fly and returning it as a relay-signed ephemeral event on that subscription. NIP-43 requires relays to opt in to this explicitly. Requesters must be authenticated via NIP-42, and info.self must match the relay’s signing pubkey. Defaults to false.
nip43.inviteRequestWhitelistPublic keys allowed to request kind 28935 invite codes. Empty (the default) means any authenticated pubkey may request one; a non-empty list restricts minting to those pubkeys.
nip45.enabledEnable or disable NIP-45 COUNT handling. Defaults to true.
nip50.enabledEnable or disable NIP-50 full-text search. Defaults to false. When enabled, clients can include a search field in REQ filters to perform text queries against event content. Requires the GIN full-text index migration.
nip50.languagePostgreSQL text-search configuration name. Defaults to simple (language-agnostic tokenization). Set to english, spanish, etc. for stemming support. See PostgreSQL text search configurations. Note: The GIN index migration is built with the simple configuration. If you change this value, you must manually rebuild the index: DROP INDEX CONCURRENTLY events_content_fts_idx; CREATE INDEX CONCURRENTLY events_content_fts_idx ON events USING gin (to_tsvector('<your_language>', event_content)); — otherwise the planner cannot use the index and queries fall back to sequential scans.
nip50.maxQueryLengthMaximum length of the search query string. Queries exceeding this are truncated. Defaults to 256.
nip56.enabledEnable NIP-56 content reporting. When true, kind-1984 report events are stored and scored by the reporter’s WoT distance from wot.seedPubkey. Defaults to false. If wot.enabled is false, every non-moderator report is still stored, but its WoT distance is always undefined, so it scores weight 0 and never becomes actionable — easy to misread as a misconfiguration. reports rows have no automatic retention/pruning: they can outlive the kind-1984 event that produced them (which is itself subject to normal event retention/deletion) and accumulate indefinitely; operators who want bounded growth need to prune the table themselves.
nip56.trustedModeratorsPubkeys (hex) whose reports are always maximum-weight and actionable, regardless of WoT distance. Reports from any other pubkey are stored and weighted, but never trigger automatic actions on their own. Defaults to [].
nip56.hideActionableReportsWhen true, events matching an actionable report are excluded from REQ/COUNT results: a pubkey-targeted report hides every event from that pubkey, an event-targeted report hides just that event. Has no effect unless nip56.enabled is also true. Defaults to false, so enabling reporting alone never changes what existing subscribers see. Requires the reports_actionable_reported_event_id_idx/reports_actionable_reported_pubkey_idx partial indexes (added by migration) to stay efficient at scale.
nip66.dnsCacheTtlSecondsDNS cache TTL in seconds for repeated probe lookups of the same hostname. Defaults to 300.
nip66.enabledEnable NIP-66 relay monitoring. When true, starts a relay-monitor cluster worker that probes targets on an interval and stores the latest snapshot in Redis. Defaults to false.
nip66.probeIntervalSecondsSeconds between scheduled relay probe runs. Defaults to 3600.
nip66.targetsPublic WebSocket URLs to probe (for example wss://relay.example.com). When empty, defaults to info.relay_url. Addresses from mirroring.static[] are probed for the admin snapshot but are not published as kind 30166 discovery events.
nip66.geohashOptional NIP-52 geohash describing this monitor’s network vantage. Published on kind 10166 monitor announcements when set.
nip66.timeouts.dnsMsDNS probe timeout in milliseconds. Defaults to 10000.
nip66.timeouts.nip11MsNIP-11 fetch timeout in milliseconds. Defaults to 10000.
nip66.timeouts.tlsMsTLS probe timeout in milliseconds. Defaults to 10000.
nip66.timeouts.wsRttMsWebSocket open RTT probe timeout in milliseconds. Defaults to 10000.
nip77.enabledEnable NIP-77 (Negentropy) set-reconciliation sync, so clients and other relays can find which events differ without downloading them all. Defaults to false. Only answers when eventStore.backend is postgres; other backends bring their own negentropy implementation. While active, the relay lists 77 in the NIP-11 supported_nips; it is left out when this is off or another backend is used. All nip77.* settings can be edited in the admin console and the CLI settings menu. When nip42.restrictedReads is enabled, reconciliation would list the ids of restricted events, so a NEG-OPEN filter that could match one (it names a restricted kind or no kinds at all) is only accepted when scoped by authors or #p to pubkeys the client has authenticated as, and is re-checked on every NEG-MSG; otherwise the session is closed with NEG-ERR auth-required:. Each open session holds the ids of every event matching its filter in memory, so size the limits below for your hardware.
nip77.maxEventsPerSessionMost events one session may cover. A NEG-OPEN whose filter matches more is rejected with NEG-ERR blocked: (clients should split the sync into since/until windows). The filter’s limit is ignored, since reconciliation needs the whole set. Defaults to 100000.
nip77.maxSessionsPerConnectionConcurrent negentropy sessions one websocket connection may hold; opening an id that is already open replaces it. Further NEG-OPENs are rejected with NEG-ERR blocked:. Defaults to 3.
nip77.sessionIdleTimeoutMsA session that receives no NEG-MSG for this many milliseconds is closed with NEG-ERR closed:. Defaults to 60000.
paymentProcessors.lnbits.baseURLBase URL of your Lnbits instance.
paymentProcessors.lnbits.callbackBaseURLPublic-facing Nostream’s Lnbits Callback URL. (e.g. https://relay.your-domain.com/callbacks/lnbits)
paymentProcessors.lnurl.invoiceURLLUD-06 Pay Request provider URL. (e.g. https://getalby.com/lnurlp/your-username)
paymentProcessors.zebedee.baseURLZebedee’s API base URL.
paymentProcessors.zebedee.callbackBaseURLPublic-facing Nostream’s Zebedee Callback URL (e.g. https://relay.your-domain.com/callbacks/zebedee)
paymentProcessors.zebedee.ipWhitelistList with Zebedee’s API Production IPs. See ZBD API Documentation for more info.
payments.enabledEnabled payments. Defaults to false.
payments.feeSchedules.admission[].amountAdmission fee amount in msats.
payments.feeSchedules.admission[].enabledEnables admission fee. Defaults to false.
payments.feeSchedules.admission[].whitelists.event_kindsList of event kinds to waive admission fee. Use [min, max] for ranges.
payments.feeSchedules.admission[].whitelists.pubkeysList of pubkeys to waive admission fee.
payments.processorEither zebedee, lnbits, lnurl.
workers.countNumber of workers to spin up to handle incoming connections.
Spin workers as many CPUs are available when set to zero. Defaults to zero.
limits.message.ipWhitelistList of IPs (IPv4 or IPv6) to ignore rate limits.
limits.admissionCheck.rateLimits[].periodRate limiting period in milliseconds. For sliding_window: the time window. For ewma: the half-life of the decay function.
limits.admissionCheck.rateLimits[].rateMaximum number of admission checks during period.
limits.admissionCheck.ipWhitelistList of IPs (IPv4 or IPv6) to ignore rate limits.
limits.rateLimiter.strategyRate limiting strategy. Either ewma or sliding_window. Defaults to ewma. When using ewma, the period field in each rate limit serves as the half-life for the exponential decay function. Note: when switching from sliding_window to ewma, consider increasing rate values slightly as EWMA penalizes bursty behavior more aggressively.
mirroring.static[].addressAddress of mirrored relay. (e.g. ws://100.100.100.100:8008)
mirroring.static[].filtersSubscription filters used to mirror.
mirroring.static[].limits.eventEvent limit overrides for this mirror. See configurations under limits.event.
mirroring.static[].secretSecret to pass to relays. Nostream relays only. Optional.
mirroring.static[].skipAdmissionCheckDisable the admission fee check for events coming from this mirror.
network.maxPayloadSizeMaximum number of bytes accepted per WebSocket frame
network.remoteIpHeaderHTTP header from proxy containing IP address from client.
network.trustedProxiesOptional allow-list of proxy IPs allowed to set network.remoteIpHeader; otherwise socket remote IP is used.
nip05.domainBlacklistList of domains blocked from NIP-05 verification. Authors with NIP-05 at these domains will be rejected.
nip05.domainWhitelistList of domains allowed for NIP-05 verification. If set, only authors verified at these domains can publish.
nip05.maxConsecutiveFailuresNumber of consecutive verification failures before giving up on an author. Defaults to 20.
nip05.modeNIP-05 verification mode: enabled requires verification, passive verifies without blocking, disabled does nothing. Defaults to disabled.
nip05.verifyExpirationTime in milliseconds before a successful NIP-05 verification expires and needs re-checking. Defaults to 604800000 (1 week).
nip05.verifyUpdateFrequencyMinimum interval in milliseconds between re-verification attempts for a given author. Defaults to 86400000 (24 hours).
paymentProcessors.lnbits.baseURLBase URL of your Lnbits instance.
paymentProcessors.lnbits.callbackBaseURLPublic-facing Nostream’s Lnbits Callback URL. (e.g. https://relay.your-domain.com/callbacks/lnbits)
paymentProcessors.lnurl.invoiceURLLUD-06 Pay Request provider URL. (e.g. https://getalby.com/lnurlp/your-username)
paymentProcessors.zebedee.baseURLZebedee’s API base URL.
paymentProcessors.zebedee.callbackBaseURLPublic-facing Nostream’s Zebedee Callback URL (e.g. https://relay.your-domain.com/callbacks/zebedee)
paymentProcessors.zebedee.ipWhitelistList with Zebedee’s API Production IPs. See ZBD API Documentation for more info.
payments.enabledEnabled payments. Defaults to false.
payments.feeSchedules.admission[].amountAdmission fee amount in msats.
payments.feeSchedules.admission[].enabledEnables admission fee. Defaults to false.
payments.feeSchedules.admission[].whitelists.event_kindsList of event kinds to waive admission fee. Use [min, max] for ranges.
payments.feeSchedules.admission[].whitelists.pubkeysList of pubkeys to waive admission fee.
payments.processorEither zebedee, lnbits, lnurl, nodeless, opennode, nwc.
workers.countNumber of workers to spin up to handle incoming connections. Spin workers as many CPUs are available when set to zero. Defaults to zero.
wot.enabledEnables the Web of Trust graph, rooted at wot.seedPubkey, built from NIP-02 contact lists. Defaults to false.
wot.maxDepthHow many hops out from wot.seedPubkey the trust graph extends. Direct follows are distance 1. Defaults to 2.
wot.minimumFollowersMinimum number of already-trusted accounts that must follow a pubkey before it enters the graph at 2+ hops. Direct follows are always trusted. Defaults to 1.
wot.refreshIntervalHoursReserved for a future periodic full rebuild; not yet read by any code (real-time kind-3 ingestion already keeps the graph current). Defaults to 24.
wot.seedPubkeyThe relay owner’s pubkey in hex. Root of the trust graph. Required when wot.enabled is true.
Edit this page on GitHub →