Risoluzione dei problemi
Gli errori più probabili — porte, permessi, TLS, NIP mancanti, pubblicazione e timeout — con soluzioni passo passo.
Tre cose da controllare prima:
nostrfy checkconvalida la configurazione (la maggior parte degli errori sono errori di configurazione).tail -f nostrfy.logmostra il log — la causa è quasi sempre lì.nostrfy restartriavvia il demone in modo pulito.
Impossibile avviare
error: cannot bind to 0.0.0.0:80: Permission denied
Causa: Solo l’utente root può fare bind sulla porta 80.
Correzione: Esegui con sudo oppure cambia la porta con una come 8080.
# Cambia port = 8080 nel file di configurazione, poi:
nostrfy --config nostrfy.toml starterror: cannot bind to ...: Address already in use
Causa: Un altro processo (un vecchio nostrfy o un altro server) sta già usando la porta.
Correzione:
ss -tlnp | grep :8080# Se nostrfy è in esecuzione, riavvialo
nostrfy --config nostrfy.toml restartalready running (pid 1234); use 'nostrfy stop' or 'nostrfy restart'
Causa: nostrfy è già in esecuzione; start si rifiuta di avviare una seconda
istanza.
Correzione: Usa nostrfy restart oppure usa semplicemente l’istanza in esecuzione.
nostrfy stop si blocca / did not stop in time
Causa: Il demone è bloccato o non risponde.
Correzione:
ps aux | grep nostrfy
kill -9 <PID>
# Rimuovi il file pid obsoleto se presente
rm -f nostrfy.piderror: invalid nostrfy.toml: TOML parse error
Causa: Il file di configurazione non è TOML valido. Errori comuni: dimenticare le virgolette intorno a una stringa o scrivere due volte la stessa chiave.
Correzione: Il messaggio di errore include un numero di riga. Controlla e correggi quella riga.
# Esempi corretti
name = "my relay" # le stringhe vanno tra virgolette con "
port = 8080 # i numeri vanno senza virgolette
enabled_nips = [1, 50] # le liste vanno tra [ ]error: cannot read nostrfy.toml: No such file or directory
Causa: Il file di configurazione non esiste.
Correzione:
nostrfy --config nostrfy.toml initerror: relay.private_key is not a valid secp256k1 secret key
Causa: relay.private_key non è una chiave esadecimale valida di 64 caratteri.
Correzione: Esegui nostrfy genkey per generare una chiave corretta (oppure imposta private_key = "").
Molti avvisi nel log all’avvio
Le righe di log [WARN] segnalano problemi di configurazione. Le principali:
| Avviso | Significato e soluzione |
|---|---|
relay.public_url is empty and server.host is "0.0.0.0"... | public_url non è impostato — l’autenticazione NIP-42, NIP-62 vanish e l’autenticazione
admin NIP-98 non funzioneranno. Imposta wss://your-public-url. |
relay.private_key is empty while NIP-29 is enabled... | I gruppi hanno bisogno di una chiave segreta. Esegui nostrfy genkey. |
unknown config key [relay].software is ignored | Una chiave legacy inutilizzata (o un refuso) nella configurazione. Controlla il nome della chiave. |
unknown config section [serve] is ignored | Un refuso nel nome di una sezione (es. [serve] invece di [server]).
Correggilo. |
relay.require_auth is true but relay.send_auth_challenge is false... | Questa combinazione blocca fuori tutti. Cambia una delle due. |
relay.require_pow = 64 ... practically unmineable | Il requisito PoW è così alto che nessuno può pubblicare. Abbassa require_pow. |
Impossibile connettersi o comportamento anomalo
Il client riceve connection refused
Causa: Il relay non è in esecuzione oppure un firewall sta bloccando la porta.
Correzione:
curl http://127.0.0.1:8080/health
# Dall'esterno (usando IP/porta del server)
curl http://YOUR_SERVER_IP:8080/health
# Controlla il firewall (esempio: ufw)
sudo ufw status
# Apri la porta se necessario
sudo ufw allow 8080I client esterni non si connettono, quelli locali sì
Causa: server.host è ancora 127.0.0.1 (il valore predefinito),
che accetta solo connessioni locali.
Correzione: Imposta host = "0.0.0.0" nella configurazione e riavvia.
Impossibile connettersi tramite un tunnel Cloudflare
Quando si usa Cloudflare Tunnel:
- Il relay funziona in HTTP in chiaro; Cloudflare termina TLS, quindi i client usano
wss://. Impostapublic_url = "wss://..."sul relay (così l’autenticazione NIP-42 funziona). - Cloudflare aggiunge un’intestazione
X-Forwarded-Proto. nostrfy tratta i valoriws/wss/http/httpsallo stesso modo, quindi normalmente non è necessaria alcuna configurazione aggiuntiva.
error: message too large e la connessione si chiude
Causa: Un singolo messaggio supera max_ws_message_bytes (predefinito 1 MB).
Correzione: Aumenta limits.max_ws_message_bytes se ti servono eventi più grandi — ma
controlla anche i limiti del client.
Errori too many subscriptions / too many filters
Causa: Sono stati raggiunti i limiti per connessione (sottoscrizioni predefinite 20, filtri predefiniti 20).
Correzione: Aumenta limits.max_subscriptions / limits.max_filters (e controlla le impostazioni del client).
Le nuove connessioni vengono rifiutate sotto carico
Causa: È stato raggiunto max_connections (predefinito 10000), è scattato il limite per IP
(max_connections_per_ip, predefinito 64), oppure il limite di connessioni al secondo per IP
(max_connections_per_sec_per_ip) ha rifiutato il picco. I limiti si applicano a ogni connessione —
WebSocket e HTTP in chiaro allo stesso modo.
Correzione: Rivedi e regola le impostazioni. max_connections_per_ip = 0 disabilita
il limite per IP; max_connections_per_sec_per_ip = 0 disabilita il limite di frequenza. Queste tre
impostazioni richiedono un riavvio.
Le connessioni cadono dopo un po’
Causa: Se ws_idle_timeout_secs è impostato, le connessioni inattive vengono chiuse.
I client sani rispondono al PING del relay con un PONG e restano connessi; solo i peer morti vengono rimossi.
Correzione: È intenzionale — il valore predefinito è 300 secondi. Imposta ws_idle_timeout_secs = 0 per disabilitarlo del tutto.
Una sottoscrizione termina con CLOSED ... response too large
Causa: Gli eventi memorizzati di una REQ hanno superato max_req_response_bytes (predefinito 32 MiB). Succede solo con eventi molto grandi o filtri molto ampi.
Correzione: Restringi il filtro (since/until più stretti, un limit più basso) oppure aumenta max_req_response_bytes (0 disabilita il budget).
Un NIP manca dall’elenco NIP-11 supported_nips
Causa: L’elenco annunciato è dinamico — un NIP viene nascosto quando tutti i kind che
definisce sono rifiutati: sono tutti in blocked_kinds, nessuno di essi è in allowed_kinds, oppure sono kind effimeri rifiutati da reject_ephemeral.
NIP-29/43/66 richiedono inoltre relay.private_key e NIP-86 richiede rpc.management_token o rpc.admin_pubkey.
Correzione: Controlla le liste di accesso attive — NIP-86 listallowedkinds mostra la
allowlist dei kind, e GET / mostra immediatamente il supported_nips effettivo.
Rimuovi il kind bloccante o l’impostazione reject_ephemeral.
Errori durante la pubblicazione
Quando la pubblicazione fallisce, il 4° elemento del messaggio OK spiega il motivo. I più comuni:
| Errore | Significato e soluzione |
|---|---|
invalid: signature verification failed | La firma dell’evento non è valida (forse una chiave client danneggiata). |
invalid: content too large | Il contenuto supera max_content_bytes (predefinito 64K caratteri). Accorcialo oppure
aumenta il limite. |
invalid: too many tags | Più tag rispetto a max_tags (predefinito 2000). |
invalid: event creation date is in the future | Timestamp troppo nel futuro (oltre max_created_at_future_secs). |
mute: event contains secret key material | Il contenuto o i tag contengono una stringa che assomiglia a un nsec. Non pubblicare mai chiavi segrete. Rimuovi la stringa e l’evento verrà accettato. |
duplicate: event already stored | Lo stesso evento è già memorizzato (normale). |
blocked: pubkey not allowed | La pubkey è bannata (banpubkey) o fuori dalla allowlist. |
blocked: kind not allowed | Questo kind non è consentito. |
rate-limited: too many events | La pubkey ha superato max_events_per_min_per_pubkey (finestra scorrevole di 60
secondi). Aspetta un minuto e riprova, oppure aumenta/disabilita il limite. |
blocked: event has been banned | L’id dell’evento è bannato. |
blocked: event has been deleted | Ripubblicazione di un evento eliminato. |
auth-required: ... | È richiesta l’autenticazione (quando relay.require_auth è attivo). |
restricted: your account is too new | L’account è stato creato entro new_pubkey_min_age_secs. Aspetta e riprova. |
restricted: unknown group | Il gruppo non esiste (crealo prima). |
restricted: this group is closed | Il gruppo è closed; le richieste di partecipazione senza codice di invito non vengono accolte. |
Server di file Blossom
Caricamento non riuscito con 401
L’evento di autorizzazione al caricamento (kind 24242) è stato rifiutato. Verifica che:
- il tag
expirationdel token sia presente e impostato a un timestamp unix futuro, - per upload/media/delete il token contenga un tag
xcon lo sha256 del blob, - il tag
server(quando presente) indichi esattamente ilblossom.hostconfigurato (solo hostname, senza schema/percorso), - il token sia stato firmato negli ultimi 10 minuti (una finestra di freschezza contro il replay),
- e la chiave di firma sia quella dell’uploader stesso.
Caricamento non riuscito con 403
blossom.restrict_uploads = true è impostato e la pubkey non è nella allowlist — aggiungila
con nostrfy blossom allow npub1... (il demone ricarica automaticamente). Se l’elenco sembra
sbagliato, nostrfy blossom list lo mostra.
Caricamento non riuscito con 409
Il client ha inviato un’intestazione X-SHA-256 che non corrisponde al corpo effettivo della richiesta (l’hash
dichiarato è stato calcolato su byte diversi — ad es. il file è cambiato tra il calcolo dell’hash e l’invio).
I client possono omettere del tutto l’intestazione.
GET / sull’host multimediale serve il documento NIP-11
La richiesta non ha raggiunto il relay con l’intestazione Blossom Host. Punta media.example.com (o qualunque sia il blossom.host impostato) alla stessa porta nel reverse proxy, poi nostrfy restart.
Un blob dà 404 subito dopo il caricamento
Il file è indirizzato per contenuto tramite il suo SHA-256: recuperalo con l’hash esatto restituito nella risposta
di caricamento (/<sha256> oppure /<sha256>.<ext>). Una mancata corrispondenza significa
che il client ha richiesto un hash diverso dai byte inviati.
Ricerca, gruppi e autenticazione
La ricerca restituisce 0 risultati / risultati inattesi
La ricerca di nostrfy corrisponde a parole intere. Nota che:
search = "rust"corrisponde agli eventi contenenti la parola "rust", ma"ru"NON corrisponde a "rust" come sottostringa.- Vengono cercate solo le parole nel contenuto dell’evento.
- Se
search_index = false, la ricerca funziona comunque ma è più lenta. - Se NIP-50 è disabilitato (
disabled_nips = [50]),searchviene ignorato (viene inviato un NOTICE).
Metadati del gruppo (39000-39005) non generati
Causa: relay.private_key non è impostato. Gli snapshot dei gruppi sono firmati dalla
chiave stessa del relay, quindi senza di essa non viene generato nulla.
Correzione:
nostrfy --config nostrfy.toml genkey
nostrfy --config nostrfy.toml restartrestricted: unknown group rifiuta gli eventi di gruppo
Causa: Il gruppo non esiste. In NIP-29, gli eventi di moderazione e le richieste di partecipazione (9021) non possono fare riferimento a un gruppo prima che sia stato creato (kind 9007).
Correzione: Crea prima il gruppo con un evento 9007.
restricted: you are not an admin of this group
Causa: La moderazione (aggiunta di membri, ecc.) richiede un admin (un membro con un ruolo). Il creatore è un admin.
Correzione: Chiedi a un admin di assegnarti un ruolo oppure crea il tuo gruppo.
restricted: this group is closed
Causa: Il gruppo è closed; le richieste di partecipazione senza codice di invito non
vengono approvate automaticamente.
Correzione: Chiedi a un admin un codice di invito (9009) e partecipa con un tag code.
Uscita accidentale da un gruppo, oppure il gruppo non ha admin
Causa: Le richieste di uscita NIP-29 (kind 9022) vengono onorate per qualsiasi membro — incluso l’ultimo admin del gruppo, che non lascia admin dietro di sé. Senza admin, nessuno può più inviare eventi di moderazione (9000/9001/9002/9008).
Correzione: Firma un evento di moderazione con la chiave stessa del relay (relay.private_key,
la pubkey annunciata come self di NIP-11). Secondo NIP-29, gli eventi di moderazione possono venire dalla "chiave
master del relay o ... dagli admin del gruppo", quindi il relay accetta la moderazione firmata dalla propria chiave anche
quando il gruppo non ha admin. Per esempio, ripristina un admin con un kind:9000:
{
"kind": 9000,
"pubkey": "<relay self pubkey>",
"tags": [["h", "<group-id>"], ["p", "<member-hex>", "admin"]]
}Firmalo e pubblicalo con la chiave del relay. In alternativa, elimina il gruppo con un kind:9008 firmato dal relay (i suoi eventi memorizzati vengono eliminati) e ricrealo con kind:9007.
Questo ripristino richiede che relay.private_key sia configurato.
Gli eventi protetti vengono rifiutati con auth-required
Causa: Gli eventi protetti NIP-70 (con tag -) possono essere pubblicati solo dall’autore
autenticato sulla stessa connessione.
Correzione: Abilita l’autenticazione NIP-42 nel client prima di pubblicare.
AUTH (NIP-42) restituisce false
Cause comuni:
relay.public_urlnon impostato o errato — il tagrelaydell’evento AUTH non corrisponde all’URL del relay. Impostawss://...e riavvia.- Challenge scaduta — hai inviato AUTH su una connessione diversa oppure hai riutilizzato una vecchia challenge.
- L’orologio del client è sballato — il
created_atdell’evento AUTH deve essere entro ±10 minuti da adesso.
L’API di gestione NIP-86 restituisce 401 unauthorized
Causa: Credenziali mancanti o errate.
Correzione:
- Imposta
management_tokene inviaAuthorization: Bearer <token>. - Oppure imposta
admin_pubkeye invia un evento di autenticazione NIP-98 (il tagudeve corrispondere esattamente all’URL del relay; è richiesto un tagpayload). - Se nessuno dei due è impostato, l’API di gestione è del tutto disabilitata.
Gli eventi di autenticazione NIP-98 vengono rifiutati per schema o porta diversi
La specifica NIP-98 dice che il tag u deve essere esattamente uguale all’URL assoluto della
richiesta, quindi nostrfy deriva l’URL atteso da relay.public_url: la sua authority più lo
schema HTTP mappato dallo schema WebSocket (wss:// → https://, ws:// → http://, nostr+ rimosso). Senza public_url il relay si aspetta il semplice http://host:port che serve. Un tag con
un altro schema, una porta diversa/omessa, oppure un percorso o una query diversi viene rifiutato — imposta relay.public_url all’indirizzo pubblico firmato dai client. Ogni evento di autenticazione è inoltre monouso: ripetere la stessa intestazione Authorization entro la sua finestra di validità di 60
secondi viene rifiutato.
Database e disco
database map is full: increase database.max_map_size
Causa: Il limite di memory-map di LMDB (predefinito 1 TB di spazio di indirizzi virtuali; l’uso reale del disco cresce con i dati) è stato raggiunto — in pratica, il database è pieno.
Correzione: Aumenta database.max_map_size e riavvia.
disk is full: refusing to commit N events
Causa: Meno di 32 MB di spazio libero su disco. Le scritture si fermano (per proteggere i dati); le letture continuano.
Correzione: Libera spazio su disco. Le scritture riprendono automaticamente quando c’è spazio disponibile.
(df -h /path/to/data)
nostrfy check riporta map_size must not exceed max_map_size
Causa: database.map_size è maggiore di max_map_size.
Correzione: Imposta map_size pari o inferiore a max_map_size (i valori predefiniti
vanno bene).
Controllo della dimensione del database
curl http://127.0.0.1:8080/relay/stats
# => "db_size_bytes" in byteBackup / spostamento del database
Tutti i dati si trovano nella directory database.path. Ferma il relay prima di copiare (copiare un database attivo può corromperlo).
nostrfy --config nostrfy.toml stop
cp -a ./data ./data-backup
# Fai anche il backup di [blossom].local_path se usi lo storage Blossom locale.
nostrfy --config nostrfy.toml startFunzionamento del demone
nostrfy stats dice nostrfy is not running (no stats file)
Causa: Il file delle statistiche non esiste — il demone non è in esecuzione oppure è stato avviato da meno di qualche secondo.
Correzione: Esegui nostrfy start, aspetta qualche secondo e riprova.
Il log cresce senza limiti
Causa: max_log_size_bytes è 0 (rotazione disabilitata).
Correzione: Imposta max_log_size_bytes = 52428800 (50 MB) e max_log_files = 5. La rotazione è automatica.
Le modifiche alla configurazione non hanno effetto dopo il ricaricamento
Causa: Hai ricaricato (SIGHUP) impostazioni fissate all’avvio: private_key, api_host, metrics_enabled, impostazioni LiveKit e
le liste di abilitazione/disabilitazione dei NIP.
Correzione: Usa nostrfy restart. Il log segnala in questo caso che «è necessario un riavvio».
Il relay continua a morire da solo
Causa: La macchina si è riavviata oppure il relay ha esaurito la memoria (OOM).
Correzione:
- Controlla la fine del log:
tail -50 nostrfy.log. - Controlla se la macchina si è riavviata:
uptime(un uptime molto breve significa un riavvio). - Controlla la memoria:
free -h. - Avvia di nuovo il relay:
nostrfy start.
systemd non riesce ad avviare il relay sulla porta 80
Un servizio systemd in esecuzione come root può associare la porta 80. Se hai impostato User= a un utente normale,
usa una porta più alta (es. 8080) oppure aggiungi AmbientCapabilities=CAP_NET_BIND_SERVICE all’unità.
Ancora non risolto?
- Controlla il log:
tail -100 nostrfy.log— di solito indica la causa diretta. - Riconvalida la configurazione:
nostrfy check— mostra avvisi ed errori. - Raccogli i dettagli di riproduzione: cosa stavi facendo, quale client, quale errore esatto.
- Chiedi nel repository del progetto: https://github.com/iqbqioza/nostrfy — quando apri una issue, includi i passaggi di riproduzione e il log.