Grundlagen
Die Konfiguration ist eine TOML-Datei,
standardmäßig nostrfy.toml genannt. Erstellen Sie sie mit init:
nostrfy --config nostrfy.toml init
Validieren Sie sie (vor jedem Start empfohlen):
nostrfy --config nostrfy.toml check
Jeder Befehl akzeptiert --config <path> (Standard nostrfy.toml).
Allgemeine Syntax:
[section]
key = "string"
key = 8080
key = [1, 2]
key = true
Konfigurationsabschnitte
| Abschnitt | Zweck |
|---|
[relay] | Identität, URLs und NIP-Schalter |
[server] | Netzwerk-Bindung, API-Trennung, Metriken |
[rpc] | NIP-86-Verwaltungs-RPC (Auth, Body-Limit) |
[limits] | Alle Limits und Überlastschutzmaßnahmen |
[database] | LMDB-Speicher, Suchindex, Queue-Begrenzungen |
[daemon] | PID-, Log- und Statistikdateien sowie Rotation |
[access] | Initiale Zugriffskontrolllisten (zur Laufzeit änderbar) |
[blossom] | Blossom-Dateiserver (Medien-Hosting) |
Jeder Schlüssel ist optional; ein fehlender Schlüssel verwendet seinen Standardwert.
Abschnitt [relay] — Relay-Identität
| Schlüssel | Typ | Standard | Beschreibung |
|---|
name | string | "nostrfy" | Relay-Name, der Clients per NIP-11 angezeigt wird |
description | string | "A minimal and stable Nostr relay" | Relay-Beschreibung (NIP-11) |
pubkey | string (64 hex) | "" | Öffentlicher Schlüssel des Administrators (NIP-11-pubkey-Feld) |
contact | string | "" | Kontakt-URI des Administrators (mailto: oder https://) |
icon | string | "" | Relay-Icon-Bild-URL |
post_policy | string | "" | URL zur Posting-Richtlinie des Relays |
private_key | string (64 hex) | "" | Der eigene geheime Schlüssel des Relays; erforderlich für NIP-29-Gruppen |
public_url | string | "" | Öffentliche URL, z. B. wss://relay.example.com |
livekit_url | string | "" | LiveKit-Server-URL für NIP-29-Audio-/Videoräume |
livekit_api_key | string | "" | LiveKit-API-Schlüssel |
livekit_api_secret | string | "" | LiveKit-API-Secret (zum Signieren von JWTs) |
enabled_nips | array of integers | [] | Explizite NIP-Allowlist |
disabled_nips | array of integers | [] | Zu deaktivierende NIPs (ignoriert, wenn enabled_nips nicht leer ist) |
reject_ephemeral | boolean | false | NIP-01-ephemere Events ablehnen (Kinds 20000–29999) |
enabled_git | boolean | false | NIP-34-Git-Events akzeptieren (Kinds 1617–1633, 30617/30618) |
require_pow | integer | 0 | Erforderlicher Proof-of-Work in führenden Null-Bits |
new_pubkey_min_age_secs | integer | 0 | Events von Pubkeys ablehnen, die jünger sind als dieser Wert (Sekunden; 0 = aus) |
max_events_per_min_per_pubkey | integer | 0 | Veröffentlichungs-Ratenlimit pro Pubkey (pro Minute; 0 = kein Limit) |
max_groups | integer | 1000 | Obergrenze für den In-Memory-NIP-29-Gruppenspeicher |
require_auth | boolean | false | NIP-42-Authentifizierung für REQ/EVENT/COUNT/NEG erfordern |
send_auth_challenge | boolean | true | AUTH-Challenge bei Verbindung senden |
enabled_nip78_auth | boolean | true | NIP-42-AUTH vor Annahme von Kind-78/30078-Events erfordern |
enabled_command_events | boolean | false | Kind:1-Operatorbefehle ausführen, die vom Admin-Pubkey verfasst wurden |
Details zu Schlüsseln
- private_key — der eigene geheime Schlüssel des Relays, verwendet zum Signieren Relay-generierter Events: NIP-29-Gruppenmetadaten (39000–39005) und NIP-43-Rollen-/Mitgliedschafts-Events. Generieren Sie ihn mit
nostrfy genkey; halten Sie ihn geheim. Er wird einmal beim Start gelesen, daher erfordert eine Änderung einen Neustart. - public_url — wird zur Validierung URL-tragender Tags von Clients verwendet: NIP-42-AUTH, NIP-62-Vanish und NIP-98-Admin-Auth. Wenn leer, fällt das Relay auf
host:port zurück, was niemals mit einer echten Client-URL übereinstimmt, wenn 0.0.0.0 oder 127.0.0.1 gebunden ist (eine Warnung wird geloggt). Immer setzen. - enabled_nips vs disabled_nips — die Allowlist gewinnt: wenn
enabled_nips nicht leer ist, werden nur deren NIPs beworben und disabled_nips wird ignoriert. Beides erfordert einen Neustart. - reject_ephemeral — Kinds 20000–29999 werden abgelehnt, aber die ausgenommenen Kinds, die laut NIPs weitergeleitet werden müssen, werden weiterhin weitergeleitet: 22242, 27235, 28934/28935/28936, 24133, 23194/23195, 24242 und 21059. Gilt bei SIGHUP.
- enabled_git — Opt-in für NIP-34: akzeptiert Kinds 1617–1633 und 30617/30618 und bewirbt NIP-34.
Standardmäßig aus, da Patch-Payloads groß sein können. Gilt bei SIGHUP.
Abschnitt [server] — Servereinstellungen
| Schlüssel | Typ | Standard | Beschreibung |
|---|
host | string | "127.0.0.1" | Bind-Adresse; 0.0.0.0 akzeptiert Verbindungen von überall |
port | integer | 8080 | Port (1–65535); Port 80 erfordert Root |
api_host | string | "" | Hostname, der ausschließlich für die REST-API vorgesehen ist |
metrics_enabled | boolean | true | Prometheus-Metriken unter /metrics bereitstellen |
ws_paths | string | "root" | WebSocket-Endpunktpfade: root, inbox-outbox oder all |
inbox_write_policy | string | "any" | Wer nach /inbox schreiben darf: „any“ oder „relay“ (Events müssen weiterhin einen p-Tag tragen) |
outbox_write_policy | string | "any" | Wer nach /outbox schreiben darf: „any“ (eigene Events des NIP-42-authentifizierten Pubkeys) oder „relay“ |
trusted_proxies | array of strings | [] | Reverse-Proxy-Adressen/CIDRs, deren X-Forwarded-For vertraut wird (leer = keinem Proxy vertrauen) |
Details zu Schlüsseln
- host —
0.0.0.0 bindet alle IPv4-Schnittstellen; 127.0.0.1 ist nur lokal. - port — 1–65535; Port 80 erfordert Root. Dieser eine Port bedient gemeinsam das WebSocket-Relay, das NIP-11-Dokument, die REST-API und die NIP-86-RPC.
- api_host — widmet die REST-API einem einzigen Hostnamen, sodass sich API und Relay einen
Port hinter einem Reverse-Proxy teilen können. Beim Start fixiert — erfordert einen Neustart.
- ws_paths —
root bedient nur /, inbox-outbox bedient nur /inbox und
/outbox, all bedient beides. Beim Start fixiert — erfordert einen Neustart. - trusted_proxies — listen Sie nur die eigenen Adressen des Proxys auf (Loopback für nginx/Caddy auf demselben
Host, Quellbereich des Load-Balancers in der Cloud). Wenn gesetzt, wird die Client-IP aus dem letzten nicht vertrauenswürdigen
X-Forwarded-For-Eintrag abgeleitet für die Pro-IP-Begrenzungen, das Ratenlimit, blockip und die Logs. Fügen Sie niemals
eine Adresse hinzu, die Clients direkt erreichen können — sie könnten den Header fälschen und die Pro-IP-Limits umgehen.
Beim Start fixiert — erfordert einen Neustart.
Abschnitt [rpc] — NIP-86-Verwaltung
| Schlüssel | Typ | Standard | Beschreibung |
|---|
management_token | string | "" | Bearer-Token für die Verwaltungs-APIs |
admin_pubkey | string (64 hex) | "" | Administrator-Pubkey für NIP-98-Verwaltungsauth |
max_admin_body_bytes | integer | 65536 | Body-Limit für die NIP-86-Verwaltungs-RPC |
Die NIP-86-RPC ist auf den öffentlichen POST /-Routen des Relays eingebunden — es gibt keinen separaten Verwaltungsport. management_token und admin_pubkey erscheinen in alten Anleitungen manchmal unter [server];
diese Schreibweisen sind veraltete Aliase dieser [rpc]-Schlüssel.
Abschnitt [limits] — Limits und Schutzmaßnahmen
Verbindungen und Nachrichten
| Schlüssel | Typ | Standard | Beschreibung |
|---|
max_connections | integer | 10000 | Maximale gleichzeitige Verbindungen |
max_connections_per_ip | integer | 64 | Max. Verbindungen pro Quell-IP |
max_ws_message_bytes | integer | 1048576 | Max. Bytes pro WebSocket-Nachricht/Frame |
socket_recv_buffer_kb | integer | 64 | Kernel-Empfangspuffer pro Verbindung (KiB) |
max_out_queue_bytes | integer | 262144 | Begrenzung der Ausgangsqueue pro Verbindung (Bytes) |
ws_idle_timeout_secs | integer | 300 | Untätige Verbindungen nach dieser Zeit schließen |
http_read_timeout_secs | integer | 30 | HTTP-Request-Head-Timeout (Slow-Loris-Abwehr) |
max_connections_per_sec_per_ip | integer | 0 | Max. neue Verbindungen pro Sekunde pro Quell-IP |
Abonnements und Abfragen
| Schlüssel | Typ | Standard | Beschreibung |
|---|
max_filters | integer | 20 | Max. Filter pro REQ |
max_subscriptions | integer | 20 | Max. Abonnements pro Verbindung |
max_limit | integer | 500 | Obergrenze für das REQ-Limit |
max_count | integer | 2000 | Obergrenze für COUNT-Ergebnisse |
max_sub_id_len | integer | 64 | Max. Abonnement-ID-Länge (Zeichen, nicht Bytes) |
max_sub_bytes | integer | 1048576 | Gesamte Abonnement-Filterbytes pro Verbindung |
max_req_response_bytes | integer | 33554432 (32 MB) | Obergrenze für die Gesamtbytes, die eine einzelne REQ-Antwort senden darf |
Events
| Schlüssel | Typ | Standard | Beschreibung |
|---|
max_content_bytes | integer | 65536 | Max. Event-Inhaltslänge in Zeichen |
max_tags | integer | 2000 | Max. Tags pro Event |
max_tag_value_bytes | integer | 1024 | Max. Bytes pro Tag-Wert |
max_created_at_future_secs | integer | 3600 | Tolerierte Zukunftsabweichung von created_at |
group_late_publish_secs | integer | 3600 | Tolerierte Verzögerung für NIP-29-Gruppenadmin-Events (Sekunden) |
max_neg_items | integer | 100000 | Max. Datensätze pro NIP-77-Negentropy-Sync |
Veraltete Aliase: limits.require_pow, limits.new_pubkey_min_age_secs und limits.max_indexed_words werden weiterhin als Aliase von relay.require_pow, relay.new_pubkey_min_age_secs und database.max_indexed_words akzeptiert.
REST-API
| Schlüssel | Typ | Standard | Beschreibung |
|---|
max_api_concurrent | integer | 8 | Max. gleichzeitige /api/v1-Anfragen |
max_api_limit | integer | 5000 | Obergrenze für den API-limit-Parameter |
max_api_offset | integer | 50000 | Obergrenze für den API-offset-Parameter |
max_api_fetch | integer | 55001 | Max. Over-Fetch-Fenster für Offset-Abfragen — muss max_api_offset + max_api_limit + 1 abdecken (0 = keine Begrenzung) |
max_api_search_bytes | integer | 2048 | Max. Bytes des API-search-Parameters |
Live-Fan-out
| Schlüssel | Typ | Standard | Beschreibung |
|---|
live_batch_interval_ms | integer | 20 | Wie oft Live-Events geflusht werden (ms) |
live_batch_size | integer | 32 | Max. Events pro Live-Batch |
live_buffer | integer | 65536 | Live-Fan-out-Queue-Größe |
Abschnitt [database] — Datenbank
| Schlüssel | Typ | Standard | Beschreibung |
|---|
path | string | "./data" | Datenbankverzeichnis (LMDB) |
max_dbs | integer | 32 | LMDB-max. benannte Datenbanken |
max_readers | integer | 128 | LMDB-max. gleichzeitige Leser |
map_size | integer | 1073741824 (1 GB) | Untergrenze für die Memory-Map-Größe (Bytes) |
max_map_size | integer | 1099511627776 (1 TB) | Obergrenze der Memory-Map (Bytes) |
purge_interval_secs | integer | 300 | NIP-40-Bereinigungsintervall (Sekunden) |
search_index | boolean | true | NIP-50-Wortindex aktivieren |
reader_threads | integer | 2 | Dedizierte Scan-Threads |
max_indexed_words | integer | 32 | Wörter jedes Event-Inhalts, die für die Suche indexiert werden |
meta_index | boolean | true | Metadaten-Header pro Event schreiben, der vom Scan-Prefilter verwendet wird |
disabled_fsync | boolean | false | Synchronen Disk-Flush nach jedem Schreibbatch überspringen |
db_buffer_size | integer | 2048 | Initialer WebSocket-Puffer pro Verbindung (Bytes) |
db_request_timeout_secs | integer | 30 | Wie lange eine Datenbankanfrage warten darf, bevor sie fehlschlägt |
max_db_queue_msgs | integer | 4096 | Max. wartende Nachrichten in der Queue vor Fail-Fast |
max_db_queue_events | integer | 262144 | Max. Events in wartenden Batches vor Fail-Fast |
max_db_queue_bytes | integer | 268435456 (256 MiB) | Max. Bytes wartender Datenbankanfragen vor Fail-Fast (0 = keine Byte-Begrenzung) |
Details zu Schlüsseln
- map_size — die Untergrenze für die Memory-Map: die Map wird immer mindestens so groß geöffnet.
- max_map_size — die Obergrenze, geöffnet als spärliche virtuelle Reservierung: physischer Speicher wächst nur
mit den tatsächlich geschriebenen Daten. Erhöhen Sie sie bei
database map is full. - search_index = false — die Suche funktioniert weiterhin (Ganzwortsuche im Inhalt), aber Scans
werden langsamer; auf einem winzigen VPS halbiert es die Datenbank. Für kleine Instanzen empfohlen.
- disabled_fsync — tauscht Haltbarkeit gegen Durchsatz: Schreibvorgänge landen im OS-Page-Cache und
bei Stromausfall können die neuesten Schreibvorgänge verloren gehen.
Abschnitt [daemon] — Daemon
| Schlüssel | Typ | Standard | Beschreibung |
|---|
pid_file | string | "./nostrfy.pid" | PID-Dateipfad |
log_file | string | "./nostrfy.log" | Log-Dateipfad |
stats_file | string | "./nostrfy.stats.json" | Statistikdateipfad |
stats_interval_secs | integer | 5 | Statistik-Schreibintervall (Sekunden) |
max_log_size_bytes | integer | 52428800 (50 MB) | Log-Rotationsgröße (0 = keine Rotation) |
max_log_files | integer | 5 | Aufzubewahrende rotierte Log-Generationen |
Pfade werden relativ zum Verzeichnis der Konfigurationsdatei aufgelöst, sodass sie gültig bleiben, nachdem der Daemon sein Arbeitsverzeichnis wechselt.
Abschnitt [access] — Zugriffskontrolle
| Schlüssel | Typ | Standard | Beschreibung |
|---|
restrict_relay | boolean | false | Nur allow-gelistete Pubkeys dürfen veröffentlichen |
blocked_kinds | array of integers | [] | Abzulehnende Kinds |
allowed_kinds | array of integers | [] | Kind-Allowlist; nur diese Kinds werden akzeptiert, wenn nicht leer |
blocked_ips | array of strings | [] | IP-Adressen, die beim Verbindungsaufbau abgewiesen werden |
method_grants | table: pubkey → array of strings | {} | NIP-86-Methodengrants für Nicht-Admin-Pubkeys (zur Laufzeit mit assignmethod verwaltet) |
Die Pubkey-Allow-/Deny-Listen sind keine Konfigurationsschlüssel — sie leben in der Relay-Datenbank (LMDB) und werden
zur Laufzeit verwaltet:
nostrfy relay allow npub1...
nostrfy relay deny npub1...
nostrfy relay list
- restrict_relay = true — nur die allow-gelisteten Pubkeys dürfen veröffentlichen, während
das Lesen für alle offen bleibt (jeder Client kann weiterhin abonnieren und abrufen).
- Ein denied Pubkey wird beim Veröffentlichen immer abgewiesen und beim Lesen nie bedient.
- method_grants — NIP-86-Methodengrants für Nicht-Admin-Pubkeys (Pubkey → Methodennamen, z. B. ein
Moderator mit
banevent und listbannedevents). Beim ersten Start aus der Konfiguration initialisiert,
dann zur Laufzeit mit NIP-86 assignmethod/unassignmethod verwaltet
(prüfbar mit listmethodassignees). Nur Moderations- und Lesemethoden sind übertragbar —
Berechtigungs-, Rollen-, Invite-Claim- und Relay-Identitätsverwaltung bleiben Admin-only, und ein gebannter Pubkey wird
auch mit Grants abgewiesen. Siehe die Verwaltungs-API.
Abschnitt [blossom] — Blossom-Dateiserver
| Schlüssel | Typ | Standard | Beschreibung |
|---|
host | string | "" | Hostname für den Blossom-Server (leer = deaktiviert) |
storage | string | "local" | Backend: „local“ (local_path) oder „s3“ (S3-kompatibler Bucket) |
local_path | string | "/var/lib/nostrfy/images" | Lokales Speicherverzeichnis für Mediendateien |
max_upload_bytes | integer | 20971520 (20 MB) | Max. Mediendateigröße |
min_free_bytes | integer | 33554432 (32 MB) | Festplattenspeicher, unterhalb dessen Uploads abgelehnt werden |
s3_endpoint | string | "" | S3-kompatibler Endpunkt (z. B. R2) |
s3_region | string | "" | S3-Region (R2 verwendet „auto“) |
s3_bucket | string | "" | S3-Bucket-Name |
s3_access_key | string | "" | S3-Zugangsschlüssel |
s3_secret_key | string | "" | S3-Geheimschlüssel |
restrict_uploads | boolean | false | Nur allow-gelistete Pubkeys dürfen hochladen |
Neuladen zur Laufzeit (SIGHUP)
Das Bearbeiten der Datei und Senden von kill -HUP $(cat nostrfy.pid) lädt die Konfiguration ohne
Neustart neu. Die meisten Einstellungen wirken sofort; einige sind beim Start fixiert:
| Gilt bei SIGHUP | Erfordert Neustart |
|---|
| relay.name, description, pubkey, contact, icon, post_policy, public_url | relay.private_key |
| reject_ephemeral, enabled_git, enabled_nip78_auth | relay.livekit_*, enabled_nips / disabled_nips |
| der Großteil von [limits] | api_host, trusted_proxies, metrics_enabled, ws_paths, database.*, Daemon-Größen, Limit-Obergrenzen, blossom.* |
[access] wird durch ein Neuladen nicht angewendet — die Listen werden einmal beim Start initialisiert und dann zur Laufzeit per NIP-86 verwaltet.
Das Log warnt, wenn sich eine neustartpflichtige Einstellung geändert hat, und einige beim Start erfasste Einstellungen werden beim
Neuladen nicht geprüft.
| Fehler | Lösung |
|---|
| public_url nicht gesetzt | setzen Sie wss://... |
| host auf 127.0.0.1 belassen | externe Clients können sich nicht verbinden |
| private_key nicht gesetzt bei NIP-29 | nostrfy genkey ausführen + Neustart |
| restrict_relay true mit leerer Allowlist | alle ausgesperrt |
| neustartpflichtige Schlüssel geändert und nur SIGHUP gesendet | nutzen Sie nostrfy restart |