Fehlerbehebung

Die Fehler, denen Sie am wahrscheinlichsten begegnen — Ports, Berechtigungen, TLS, fehlende NIPs, Veröffentlichen und Timeouts — mit Schritt-für-Schritt-Lösungen.

Drei Dinge zuerst prüfen:

  • nostrfy check validiert Ihre Konfiguration (die meisten Fehler sind Konfigurationsfehler).
  • tail -f nostrfy.log zeigt das Protokoll — die Ursache steht fast immer dort.
  • nostrfy restart startet den Daemon sauber neu.

Startet nicht

error: cannot bind to 0.0.0.0:80: Permission denied

Ursache: Port 80 kann nur von root gebunden werden.

Lösung: Mit sudo ausführen oder den Port z. B. auf 8080 ändern.

sh
# port = 8080 in der Konfigurationsdatei ändern, dann:
nostrfy --config nostrfy.toml start

error: cannot bind to ...: Address already in use

Ursache: Ein anderer Prozess (ein altes nostrfy oder ein anderer Server) verwendet den Port bereits.

Lösung:

sh
ss -tlnp | grep :8080
sh
# Wenn nostrfy läuft, neu starten
nostrfy --config nostrfy.toml restart

already running (pid 1234); use 'nostrfy stop' or 'nostrfy restart'

Ursache: nostrfy läuft bereits; start verweigert den Start einer zweiten Instanz.

Lösung: nostrfy restart verwenden oder einfach die laufende Instanz nutzen.

nostrfy stop hängt / did not stop in time

Ursache: Der Daemon hängt fest oder antwortet nicht.

Lösung:

sh
ps aux | grep nostrfy
kill -9 <PID>
# Veraltete Pid-Datei entfernen, falls vorhanden
rm -f nostrfy.pid

error: invalid nostrfy.toml: TOML parse error

Ursache: Die Konfigurationsdatei ist kein gültiges TOML. Typische Fehler: vergessene Anführungszeichen um einen String oder derselbe Schlüssel doppelt geschrieben.

Lösung: Die Fehlermeldung enthält eine Zeilennummer. Diese Zeile prüfen und korrigieren.

toml
# Korrekte Beispiele
name = "my relay"        # Strings werden mit " zitiert
port = 8080              # Zahlen stehen ohne Anführungszeichen
enabled_nips = [1, 50]   # Listen stehen in [ ]

error: cannot read nostrfy.toml: No such file or directory

Ursache: Die Konfigurationsdatei existiert nicht.

Lösung:

sh
nostrfy --config nostrfy.toml init

error: relay.private_key is not a valid secp256k1 secret key

Ursache: relay.private_key ist kein gültiger 64-stelliger Hex-Schlüssel.

Lösung: nostrfy genkey ausführen, um einen korrekten Schlüssel zu erzeugen (oder private_key = "" setzen).

Viele Warnungen im Protokoll beim Start

[WARN]-Zeilen weisen auf Konfigurationsprobleme hin. Die wichtigsten:

WarnungBedeutung und Lösung
relay.public_url is empty and server.host is "0.0.0.0"...public_url ist nicht gesetzt — NIP-42-Auth, NIP-62-Vanish und NIP-98-Admin-Auth funktionieren nicht. wss://your-public-url setzen.
relay.private_key is empty while NIP-29 is enabled...Gruppen brauchen einen geheimen Schlüssel. nostrfy genkey ausführen.
unknown config key [relay].software is ignoredEin ungenutzter Legacy-Schlüssel (oder Tippfehler) in der Konfiguration. Schlüsselnamen prüfen.
unknown config section [serve] is ignoredTippfehler in einem Abschnittsnamen (z. B. [serve] statt [server]). Korrigieren.
relay.require_auth is true but relay.send_auth_challenge is false...Diese Kombination sperrt alle aus. Einen der beiden Werte ändern.
relay.require_pow = 64 ... practically unmineableDie PoW-Anforderung ist so hoch, dass niemand posten kann. require_pow senken.

Kann nicht verbinden oder verhält sich seltsam

Client erhält connection refused

Ursache: Das Relay läuft nicht oder eine Firewall blockiert den Port.

Lösung:

sh
curl http://127.0.0.1:8080/health

# Von außen (mit IP/Port des Servers)
curl http://YOUR_SERVER_IP:8080/health

# Firewall prüfen (Beispiel: ufw)
sudo ufw status
# Port bei Bedarf öffnen
sudo ufw allow 8080

Externe Clients können nicht verbinden, lokale schon

Ursache: server.host steht noch auf 127.0.0.1 (Standard) und akzeptiert nur lokale Verbindungen.

Lösung: In der Konfiguration host = "0.0.0.0" setzen und neu starten.

Keine Verbindung über einen Cloudflare-Tunnel

Bei Verwendung von Cloudflare Tunnel:

  • Das Relay läuft mit plain HTTP; Cloudflare terminiert TLS, daher verwenden Clients wss://. Auf dem Relay public_url = "wss://..." setzen (damit funktioniert NIP-42-Auth).
  • Cloudflare fügt einen X-Forwarded-Proto-Header hinzu. nostrfy behandelt die Werte ws / wss / http / https gleich, daher ist normalerweise keine zusätzliche Konfiguration nötig.

error: message too large, und die Verbindung schließt sich

Ursache: Eine einzelne Nachricht überschreitet max_ws_message_bytes (Standard 1 MB).

Lösung: limits.max_ws_message_bytes erhöhen, wenn größere Events nötig sind — aber auch die Limits des Clients prüfen.

Fehler too many subscriptions / too many filters

Ursache: Die Caps pro Verbindung wurden erreicht (Subscriptions Standard 20, Filter Standard 20).

Lösung: limits.max_subscriptions / limits.max_filters erhöhen (und die Client-Einstellungen prüfen).

Neue Verbindungen werden unter Last abgewiesen

Ursache: max_connections (Standard 10000) wurde erreicht, das Cap pro IP (max_connections_per_ip, Standard 64) hat gegriffen, oder das Verbindungsratenlimit pro Sekunde und IP (max_connections_per_sec_per_ip) hat den Burst abgewiesen. Die Caps gelten für jede Verbindung — WebSocket wie plain HTTP.

Lösung: Die Einstellungen prüfen und anpassen. max_connections_per_ip = 0 deaktiviert das Cap pro IP; max_connections_per_sec_per_ip = 0 deaktiviert das Ratenlimit. Diese drei Einstellungen erfordern einen Neustart.

Verbindungen brechen nach einer Weile ab

Ursache: Wenn ws_idle_timeout_secs gesetzt ist, werden untätige Verbindungen geschlossen. Gesunde Clients beantworten das PING des Relays mit PONG und bleiben verbunden; nur tote Peers werden entfernt.

Lösung: Das ist beabsichtigt — Standard sind 300 Sekunden. Mit ws_idle_timeout_secs = 0 ganz deaktivieren.

Eine Subscription endet mit CLOSED ... response too large

Ursache: Die gespeicherten Events eines REQ haben max_req_response_bytes überschritten (Standard 32 MiB). Passiert nur bei sehr großen Events oder sehr breiten Filtern.

Lösung: Den Filter einengen (strengeres since / until, kleineres limit) oder max_req_response_bytes erhöhen (0 deaktiviert das Budget).

Ein NIP fehlt in der NIP-11-Liste supported_nips

Ursache: Die annoncierte Liste ist dynamisch — ein NIP wird ausgeblendet, wenn alle von ihm definierten Kinds abgelehnt werden: alle stehen in blocked_kinds, keiner steht in allowed_kinds, oder es sind ephemere Kinds, die per reject_ephemeral abgelehnt werden. NIP-29/43/66 erfordern zusätzlich relay.private_key, und NIP-86 erfordert rpc.management_token oder rpc.admin_pubkey.

Lösung: Die aktiven Zugriffslisten prüfen — NIP-86-listallowedkinds zeigt die Kind-Allowlist, und GET / zeigt sofort die effektiven supported_nips. Den blockierenden Kind oder die reject_ephemeral-Einstellung entfernen.

Fehler beim Veröffentlichen

Wenn das Veröffentlichen fehlschlägt, erklärt das 4. Element der OK-Nachricht den Grund. Die häufigsten:

FehlerBedeutung und Lösung
invalid: signature verification failedDie Event-Signatur ist ungültig (möglicherweise ein defekter Client-Schlüssel).
invalid: content too largeDer Inhalt überschreitet max_content_bytes (Standard 64K Zeichen). Kürzen oder das Limit erhöhen.
invalid: too many tagsMehr Tags als max_tags (Standard 2000).
invalid: event creation date is in the futureZeitstempel liegt zu weit in der Zukunft (jenseits von max_created_at_future_secs).
mute: event contains secret key materialInhalt oder Tags enthalten einen nsec-artigen String. Niemals geheime Schlüssel posten. Den String entfernen, dann wird das Event akzeptiert.
duplicate: event already storedDasselbe Event ist bereits gespeichert (normal).
blocked: pubkey not allowedDer Pubkey ist gebannt (banpubkey) oder außerhalb der Allowlist.
blocked: kind not allowedDieser Kind ist nicht erlaubt.
rate-limited: too many eventsDer Pubkey hat max_events_per_min_per_pubkey überschritten (gleitendes 60-Sekunden-Fenster). Eine Minute warten und erneut versuchen oder das Limit erhöhen/deaktivieren.
blocked: event has been bannedDie Event-ID ist gebannt.
blocked: event has been deletedErneutes Veröffentlichen eines gelöschten Events.
auth-required: ...Authentifizierung ist erforderlich (wenn relay.require_auth aktiv ist).
restricted: your account is too newDas Konto wurde innerhalb von new_pubkey_min_age_secs erstellt. Warten und erneut versuchen.
restricted: unknown groupDie Gruppe existiert nicht (zuerst erstellen).
restricted: this group is closedDie Gruppe ist closed; Beitrittsanfragen ohne Einladungscode werden nicht honoriert.

Blossom-Dateiserver

Upload schlägt mit 401 fehl

Das Upload-Autorisierungs-Event (Kind 24242) wurde abgelehnt. Prüfen, ob:

  • der expiration-Tag des Tokens vorhanden ist und auf einen Unix-Zeitstempel in der Zukunft gesetzt ist,
  • für upload/media/delete das Token einen x-Tag mit dem sha256 des Blobs trägt,
  • der server-Tag (falls vorhanden) genau den konfigurierten blossom.host nennt (nur Hostname, ohne Schema/Pfad),
  • das Token innerhalb der letzten 10 Minuten signiert wurde (Frische-Fenster gegen Replay),
  • und der Signierschlüssel dem Uploader selbst gehört.

Upload schlägt mit 403 fehl

blossom.restrict_uploads = true ist gesetzt und der Pubkey steht nicht auf der Allowlist — mit nostrfy blossom allow npub1... hinzufügen (der Daemon lädt automatisch neu). Wenn die Liste falsch aussieht, zeigt nostrfy blossom list sie an.

Upload schlägt mit 409 fehl

Der Client hat einen X-SHA-256-Header gesendet, der nicht zum tatsächlichen Request-Body passt (der deklarierte Hash wurde über andere Bytes berechnet — z. B. hat sich die Datei zwischen Hashing und Senden geändert). Clients können den Header ganz weglassen.

GET / auf dem Media-Host liefert das NIP-11-Dokument

Die Anfrage hat das Relay nicht mit dem Blossom-Host-Header erreicht. media.example.com (oder was als blossom.host gesetzt ist) im Reverse-Proxy auf denselben Port zeigen lassen, dann nostrfy restart.

Ein Blob gibt direkt nach dem Upload 404

Die Datei ist per SHA-256 inhaltsadressiert: sie über den exakten Hash aus der Upload-Antwort abrufen (/<sha256> oder /<sha256>.<ext>). Eine Abweichung bedeutet, dass der Client einen anderen Hash angefordert hat als die gesendeten Bytes.

Suche, Gruppen und Auth

Suche liefert 0 Ergebnisse / unerwartete Ergebnisse

Die nostrfy-Suche trifft ganze Wörter. Beachten, dass:

  • search = "rust" Events mit dem Wort „rust“ trifft, aber "ru" trifft „rust“ NICHT als Substring.
  • Nur Wörter im Event-Inhalt werden durchsucht.
  • Falls search_index = false, funktioniert die Suche trotzdem, ist aber langsamer.
  • Falls NIP-50 deaktiviert ist (disabled_nips = [50]), wird search ignoriert (es wird ein NOTICE gesendet).

Gruppen-Metadaten (39000-39005) werden nicht erzeugt

Ursache: relay.private_key ist nicht gesetzt. Gruppen-Snapshots werden mit dem eigenen Schlüssel des Relays signiert, ohne ihn wird nichts erzeugt.

Lösung:

sh
nostrfy --config nostrfy.toml genkey
nostrfy --config nostrfy.toml restart

restricted: unknown group weist Gruppen-Events ab

Ursache: Die Gruppe existiert nicht. In NIP-29 können Moderations-Events und Beitrittsanfragen (9021) keine Gruppe adressieren, bevor sie per Kind 9007 erstellt wurde.

Lösung: Zuerst die Gruppe mit einem 9007-Event erstellen.

restricted: you are not an admin of this group

Ursache: Moderation (Mitglieder hinzufügen usw.) erfordert einen Admin (ein Mitglied mit Rolle). Der Ersteller ist Admin.

Lösung: Einen Admin um eine Rolle bitten oder eine eigene Gruppe erstellen.

restricted: this group is closed

Ursache: Die Gruppe ist closed; Beitrittsanfragen ohne Einladungscode werden nicht automatisch genehmigt.

Lösung: Einen Admin um einen Einladungscode (9009) bitten und mit einem code-Tag beitreten.

Versehentlich eine Gruppe verlassen, oder die Gruppe hat keine Admins

Ursache: NIP-29-Austrittsanfragen (Kind 9022) werden für jedes Mitglied honoriert — auch für den letzten Admin der Gruppe, der keine Admins hinterlässt. Ohne Admin kann niemand mehr Moderations-Events (9000/9001/9002/9008) senden.

Lösung: Ein Moderations-Event mit dem eigenen Schlüssel des Relays signieren (relay.private_key, der Pubkey, der als NIP-11-self annonciert wird). Per NIP-29 dürfen Moderations-Events vom „Relay-Master-Key oder … Gruppen-Admins“ kommen, daher akzeptiert das Relay Gruppenmoderation, die mit seinem eigenen Schlüssel signiert ist, selbst wenn die Gruppe keine Admins hat. Zum Beispiel einen Admin mit kind:9000 wiederherstellen:

json
{
  "kind": 9000,
  "pubkey": "<relay self pubkey>",
  "tags": [["h", "<group-id>"], ["p", "<member-hex>", "admin"]]
}

Mit dem Relay-Schlüssel signieren und veröffentlichen. Alternativ die Gruppe mit Relay-signiertem kind:9008 löschen (ihre gespeicherten Events werden gelöscht) und mit kind:9007 neu erstellen. Diese Wiederherstellung braucht ein konfiguriertes relay.private_key.

Geschützte Events werden mit auth-required abgewiesen

Ursache: Geschützte NIP-70-Events (mit --Tag) dürfen nur vom authentifizierten Autor auf derselben Verbindung veröffentlicht werden.

Lösung: Vor dem Veröffentlichen NIP-42-Auth im Client aktivieren.

AUTH (NIP-42) gibt false zurück

Häufige Ursachen:

  1. relay.public_url ist nicht gesetzt oder falsch — der relay-Tag des AUTH-Events passt nicht zur Relay-URL. wss://... setzen und neu starten.
  2. Veraltete Challenge — AUTH wurde auf einer anderen Verbindung gesendet oder eine alte Challenge wiederverwendet.
  3. Die Client-Uhr geht falsch — created_at des AUTH-Events muss innerhalb von ±10 Minuten um jetzt liegen.

NIP-86-Verwaltungs-API gibt 401 unauthorized zurück

Ursache: Fehlende oder falsche Credentials.

Lösung:

  • management_token setzen und Authorization: Bearer <token> senden.
  • Oder admin_pubkey setzen und ein NIP-98-Auth-Event senden (der u-Tag muss exakt zur Relay-URL passen; ein payload-Tag ist erforderlich).
  • Falls beides nicht gesetzt ist, ist die Verwaltungs-API ganz deaktiviert.

NIP-98-Auth-Events werden wegen anderem Schema oder Port abgewiesen

Die NIP-98-Spezifikation sagt, der u-Tag muss exakt derselbe wie die absolute Request-URL sein, daher leitet nostrfy die erwartete URL aus relay.public_url ab: ihren Authority-Teil plus das HTTP-Schema, abgebildet aus dem WebSocket-Schema (wss:// → https://, ws:// → http://, nostr+-Präfix entfernt). Ohne public_url erwartet das Relay das plain http://host:port, das es bedient. Ein Tag mit anderem Schema, anderem/weggelassenem Port oder anderem Pfad bzw. Query wird abgewiesen — relay.public_url auf die öffentliche Adresse setzen, die Clients signieren. Jedes Auth-Event ist außerdem einmalig verwendbar: das Wiederholen desselben Authorization-Headers innerhalb seines 60-Sekunden-Gültigkeitsfensters wird abgewiesen.

Datenbank und Festplatte

database map is full: increase database.max_map_size

Ursache: Die LMDB-Memory-Map-Obergrenze (Standard 1 TB virtueller Adressraum; die tatsächliche Plattennutzung wächst mit den Daten) wurde erreicht — die Datenbank ist faktisch voll.

Lösung: database.max_map_size erhöhen und neu starten.

disk is full: refusing to commit N events

Ursache: Weniger als 32 MB freier Plattenplatz. Schreibvorgänge stoppen (zum Schutz der Daten); Lesevorgänge laufen weiter.

Lösung: Plattenplatz freigeben. Schreibvorgänge werden automatisch fortgesetzt, sobald Platz verfügbar ist. (df -h /path/to/data)

nostrfy check meldet map_size must not exceed max_map_size

Ursache: database.map_size ist größer als max_map_size.

Lösung: map_size auf oder unter max_map_size setzen (die Standards sind in Ordnung).

Datenbankgröße prüfen

sh
curl http://127.0.0.1:8080/relay/stats
# => "db_size_bytes" in Bytes

Datenbank sichern / umziehen

Alle Daten liegen im Verzeichnis database.path. Das Relay vor dem Kopieren stoppen (das Kopieren einer Live-Datenbank kann sie korrumpieren).

sh
nostrfy --config nostrfy.toml stop
cp -a ./data ./data-backup
# Auch [blossom].local_path sichern, bei lokalem Blossom-Speicher.
nostrfy --config nostrfy.toml start

Daemon-Betrieb

nostrfy stats sagt nostrfy is not running (no stats file)

Ursache: Die Stats-Datei existiert nicht — der Daemon läuft nicht oder ist erst vor wenigen Sekunden gestartet.

Lösung: nostrfy start ausführen, ein paar Sekunden warten und erneut versuchen.

Das Protokoll wächst unbegrenzt

Ursache: max_log_size_bytes ist 0 (Rotation deaktiviert).

Lösung: max_log_size_bytes = 52428800 (50 MB) und max_log_files = 5 setzen. Die Rotation ist automatisch.

Änderungen an der Konfiguration wirken nach Reload nicht

Ursache: Sie haben (per SIGHUP) Einstellungen neu geladen, die beim Start fixiert sind: private_key, api_host, metrics_enabled, LiveKit-Einstellungen und die NIP-Aktivierungs-/Deaktivierungslisten.

Lösung: nostrfy restart verwenden. Das Protokoll enthält in diesem Fall eine Warnung „a restart is required“.

Das Relay stirbt von selbst

Ursache: Die Maschine wurde neu gestartet oder dem Relay ging der Speicher aus (OOM).

Lösung:

  1. Ende des Protokolls prüfen: tail -50 nostrfy.log.
  2. Prüfen, ob die Maschine neu gestartet wurde: uptime (eine sehr kurze Uptime bedeutet einen Neustart).
  3. Speicher prüfen: free -h.
  4. Das Relay erneut starten: nostrfy start.
Tipp
Um nostrfy automatisch beim Booten zu starten, als systemd-Service registrieren, mit dem Startbefehl des Relays als ExecStart.

systemd kann das Relay auf Port 80 nicht starten

Ein als root laufender systemd-Service kann Port 80 binden. Wenn User= auf einen regulären Benutzer gesetzt ist, entweder einen höheren Port (z. B. 8080) verwenden oder AmbientCapabilities=CAP_NET_BIND_SERVICE zur Unit hinzufügen.

Immer noch nicht gelöst?

  1. Protokoll prüfen: tail -100 nostrfy.log — es nennt meist die direkte Ursache.
  2. Konfiguration erneut validieren: nostrfy check — zeigt Warnungen und Fehler.
  3. Reproduktionsdetails sammeln: was getan wurde, welcher Client, welcher exakte Fehler.
  4. Im Projekt-Repository fragen: https://github.com/iqbqioza/nostrfy — beim Erstellen eines Issues Reproduktionsschritte und Protokoll beifügen.