Nozioni di base
La configurazione è un file TOML, per impostazione predefinita chiamato nostrfy.toml. Crealo con init:
nostrfy --config nostrfy.toml init
Convalidalo (consigliato prima di ogni avvio):
nostrfy --config nostrfy.toml check
Ogni comando accetta --config <path> (predefinito nostrfy.toml).
Sintassi generale:
[section]
key = "string"
key = 8080
key = [1, 2]
key = true
Sezioni di configurazione
| Sezione | Scopo |
|---|
[relay] | Identità, URL e interruttori NIP |
[server] | Binding di rete, separazione API, metriche |
[rpc] | RPC di gestione NIP-86 (autenticazione, limite del corpo) |
[limits] | Tutti i limiti e le protezioni contro il sovraccarico |
[database] | Archiviazione LMDB, indice di ricerca, limiti di coda |
[daemon] | File PID, di log e di statistiche e rotazione |
[access] | Elenchi iniziali di controllo degli accessi (modificabili a runtime) |
[blossom] | Server di file Blossom (hosting multimediale) |
Ogni chiave è facoltativa; una chiave mancante usa il suo valore predefinito.
Sezione [relay] — identità del relay
| Chiave | Tipo | Predefinito | Descrizione |
|---|
name | string | "nostrfy" | Nome del relay mostrato ai client tramite NIP-11 |
description | string | "A minimal and stable Nostr relay" | Descrizione del relay (NIP-11) |
pubkey | string (64 hex) | "" | Chiave pubblica dell’amministratore (campo pubkey di NIP-11) |
contact | string | "" | URI di contatto dell’amministratore (mailto: o https://) |
icon | string | "" | URL dell’immagine icona del relay |
post_policy | string | "" | URL che punta alla policy di pubblicazione del relay |
private_key | string (64 hex) | "" | Chiave segreta propria del relay; richiesta per i gruppi NIP-29 |
public_url | string | "" | URL pubblico, es. wss://relay.example.com |
livekit_url | string | "" | URL del server LiveKit per stanze audio/video NIP-29 |
livekit_api_key | string | "" | Chiave API di LiveKit |
livekit_api_secret | string | "" | Segreto API di LiveKit (usato per firmare i JWT) |
enabled_nips | array of integers | [] | Allowlist esplicita di NIP |
disabled_nips | array of integers | [] | NIP da disabilitare (ignorato quando enabled_nips non è vuoto) |
reject_ephemeral | boolean | false | Rifiuta eventi effimeri NIP-01 (kind 20000-29999) |
enabled_git | boolean | false | Accetta eventi git NIP-34 (kind 1617-1633, 30617/30618) |
require_pow | integer | 0 | Proof-of-work richiesta in bit zero iniziali |
new_pubkey_min_age_secs | integer | 0 | Rifiuta eventi da pubkey più recenti di questo valore (secondi; 0 = disattivato) |
max_events_per_min_per_pubkey | integer | 0 | Limite di pubblicazione per pubkey (al minuto; 0 = nessun limite) |
max_groups | integer | 1000 | Limite dell’archivio gruppi NIP-29 in memoria |
require_auth | boolean | false | Richiedi autenticazione NIP-42 per REQ/EVENT/COUNT/NEG |
send_auth_challenge | boolean | true | Invia la challenge AUTH alla connessione |
enabled_nip78_auth | boolean | true | Richiedi AUTH NIP-42 prima di accettare eventi kind 78/30078 |
enabled_command_events | boolean | false | Esegui comandi operatore kind:1 firmati dalla pubkey dell’admin |
Dettagli delle chiavi
- private_key — la chiave segreta propria del relay, usata per firmare eventi generati dal relay: metadati dei gruppi NIP-29 (39000-39005) ed eventi di ruolo/membri NIP-43. Generala con
nostrfy genkey; tienila segreta. Viene letta una volta all’avvio, quindi modificarla richiede un riavvio. - public_url — usata per convalidare i tag con URL dai client: AUTH NIP-42, vanish NIP-62 e auth admin NIP-98. Quando è vuota, il relay ripiega su
host:port, che non corrisponde mai a una URL reale del client quando si usa il binding 0.0.0.0 o 127.0.0.1 (viene registrato un avviso). Impostala sempre. - enabled_nips vs disabled_nips — l’allowlist vince: quando
enabled_nips non è vuoto, vengono annunciati solo i suoi NIP e disabled_nips viene ignorato. Entrambi richiedono un riavvio. - reject_ephemeral — i kind 20000-29999 vengono rifiutati, ma i kind esenti che i NIP richiedono di inoltrare vengono comunque inoltrati: 22242, 27235, 28934/28935/28936, 24133, 23194/23195, 24242 e 21059. Si applica con SIGHUP.
- enabled_git — NIP-34 facoltativo: accetta i kind 1617-1633 e 30617/30618 e annuncia NIP-34. Disattivato per impostazione predefinita perché i payload delle patch possono essere grandi. Si applica con SIGHUP.
Sezione [server] — impostazioni del server
| Chiave | Tipo | Predefinito | Descrizione |
|---|
host | string | "127.0.0.1" | Indirizzo di binding; 0.0.0.0 accetta connessioni da ovunque |
port | integer | 8080 | Porta (1-65535); la porta 80 richiede root |
api_host | string | "" | Hostname dedicato all’API REST |
metrics_enabled | boolean | true | Serve metriche Prometheus su /metrics |
ws_paths | string | "root" | Percorsi dell’endpoint WebSocket: root, inbox-outbox o all |
inbox_write_policy | string | "any" | Chi può scrivere su /inbox: "any" o "relay" (gli eventi devono comunque avere un tag p) |
outbox_write_policy | string | "any" | Chi può scrivere su /outbox: "any" (i propri eventi della pubkey autenticata NIP-42) o "relay" |
trusted_proxies | array of strings | [] | Indirizzi/CIDR dei reverse proxy il cui X-Forwarded-For è attendibile (vuoto = nessun proxy attendibile) |
Dettagli delle chiavi
- host —
0.0.0.0 collega tutte le interfacce IPv4; 127.0.0.1 è solo locale. - port — 1-65535; la porta 80 richiede root. Questa singola porta serve insieme il relay WebSocket, il documento NIP-11, l’API REST e l’RPC NIP-86.
- api_host — dedica l’API REST a un singolo hostname così API e relay possono condividere una porta dietro un reverse proxy. Fisso all’avvio — richiede un riavvio.
- ws_paths —
root serve solo /, inbox-outbox serve solo /inbox e /outbox, all serve entrambi. Fisso all’avvio — richiede un riavvio. - trusted_proxies — elenca solo gli indirizzi propri del proxy (loopback per nginx/Caddy sullo stesso host, l’intervallo di origine del bilanciatore nel cloud). Se impostato, l’IP del client è derivato dall’ultima voce non attendibile di
X-Forwarded-For per i limiti per IP, il rate limit, blockip e i log. Non aggiungere mai un indirizzo raggiungibile direttamente dai client — potrebbero falsificare l’header e aggirare i limiti per IP. Fisso all’avvio — richiede un riavvio.
Sezione [rpc] — gestione NIP-86
| Chiave | Tipo | Predefinito | Descrizione |
|---|
management_token | string | "" | Token Bearer per le API di gestione |
admin_pubkey | string (64 hex) | "" | Pubkey dell’amministratore per l’auth di gestione NIP-98 |
max_admin_body_bytes | integer | 65536 | Limite del corpo per l’RPC di gestione NIP-86 |
L’RPC NIP-86 è montato sulle route pubbliche POST / del relay — non esiste una porta di gestione separata. management_token e admin_pubkey a volte compaiono sotto [server] nelle vecchie guide; quelle grafie sono alias legacy di queste chiavi [rpc].
Sezione [limits] — limiti e protezioni
Connessioni e messaggi
| Chiave | Tipo | Predefinito | Descrizione |
|---|
max_connections | integer | 10000 | Connessioni simultanee massime |
max_connections_per_ip | integer | 64 | Connessioni massime per IP di origine |
max_ws_message_bytes | integer | 1048576 | Byte massimi per messaggio/frame WebSocket |
socket_recv_buffer_kb | integer | 64 | Buffer di ricezione del kernel per connessione (KiB) |
max_out_queue_bytes | integer | 262144 | Limite della coda di uscita per connessione (byte) |
ws_idle_timeout_secs | integer | 300 | Chiudi le connessioni inattive dopo questo tempo |
http_read_timeout_secs | integer | 30 | Timeout dell’header HTTP (difesa slow-loris) |
max_connections_per_sec_per_ip | integer | 0 | Nuove connessioni massime al secondo per IP di origine |
Sottoscrizioni e query
| Chiave | Tipo | Predefinito | Descrizione |
|---|
max_filters | integer | 20 | Filtri massimi per REQ |
max_subscriptions | integer | 20 | Sottoscrizioni massime per connessione |
max_limit | integer | 500 | Tetto per il limit di REQ |
max_count | integer | 2000 | Tetto per i risultati COUNT |
max_sub_id_len | integer | 64 | Lunghezza massima dell’id di sottoscrizione (caratteri, non byte) |
max_sub_bytes | integer | 1048576 | Byte totali dei filtri di sottoscrizione per connessione |
max_req_response_bytes | integer | 33554432 (32 MB) | Tetto dei byte totali che una singola risposta REQ può inviare |
Eventi
| Chiave | Tipo | Predefinito | Descrizione |
|---|
max_content_bytes | integer | 65536 | Lunghezza massima del contenuto dell’evento in caratteri |
max_tags | integer | 2000 | Tag massimi per evento |
max_tag_value_bytes | integer | 1024 | Byte massimi per valore di tag |
max_created_at_future_secs | integer | 3600 | Scostamento futuro tollerato di created_at |
group_late_publish_secs | integer | 3600 | Ritardo tollerato per eventi admin dei gruppi NIP-29 (secondi) |
max_neg_items | integer | 100000 | Record massimi per sincronizzazione negentropy NIP-77 |
Alias legacy: limits.require_pow, limits.new_pubkey_min_age_secs e limits.max_indexed_words sono ancora accettati come alias di relay.require_pow, relay.new_pubkey_min_age_secs e database.max_indexed_words.
API REST
| Chiave | Tipo | Predefinito | Descrizione |
|---|
max_api_concurrent | integer | 8 | Richieste /api/v1 simultanee massime |
max_api_limit | integer | 5000 | Tetto per il parametro limit dell’API |
max_api_offset | integer | 50000 | Tetto per il parametro offset dell’API |
max_api_fetch | integer | 55001 | Finestra massima di over-fetch per query con offset — deve coprire max_api_offset + max_api_limit + 1 (0 = nessun limite) |
max_api_search_bytes | integer | 2048 | Byte massimi del parametro search dell’API |
Fan-out live
| Chiave | Tipo | Predefinito | Descrizione |
|---|
live_batch_interval_ms | integer | 20 | Frequenza di flush degli eventi live (ms) |
live_batch_size | integer | 32 | Eventi massimi per batch live |
live_buffer | integer | 65536 | Dimensione della coda di fan-out live |
Sezione [database] — database
| Chiave | Tipo | Predefinito | Descrizione |
|---|
path | string | "./data" | Directory del database (LMDB) |
max_dbs | integer | 32 | Massimo di database nominati LMDB |
max_readers | integer | 128 | Massimo di lettori simultanei LMDB |
map_size | integer | 1073741824 (1 GB) | Base della dimensione della mappa di memoria (byte) |
max_map_size | integer | 1099511627776 (1 TB) | Tetto della mappa di memoria (byte) |
purge_interval_secs | integer | 300 | Intervallo di purge NIP-40 (secondi) |
search_index | boolean | true | Abilita l’indice delle parole NIP-50 |
reader_threads | integer | 2 | Thread dedicati alla scansione |
max_indexed_words | integer | 32 | Parole del contenuto di ogni evento indicizzate per la ricerca |
meta_index | boolean | true | Scrivi l’header di metadati per evento usato dal prefiltro di scansione |
disabled_fsync | boolean | false | Salta il flush sincrono su disco dopo ogni batch di scrittura |
db_buffer_size | integer | 2048 | Buffer WebSocket iniziale per connessione (byte) |
db_request_timeout_secs | integer | 30 | Tempo massimo che una richiesta al database può attendere prima di fallire |
max_db_queue_msgs | integer | 4096 | Messaggi massimi in coda prima di fallire in fretta |
max_db_queue_events | integer | 262144 | Eventi massimi nei batch in coda prima di fallire in fretta |
max_db_queue_bytes | integer | 268435456 (256 MiB) | Byte massimi di richieste al database in coda prima di fallire in fretta (0 = nessun limite di byte) |
Dettagli delle chiavi
- map_size — la base della mappa di memoria: la mappa viene sempre aperta almeno con questa dimensione.
- max_map_size — il tetto, aperto come prenotazione virtuale sparsa: il disco fisico cresce solo con i dati effettivamente scritti. Aumentalo quando vedi
database map is full. - search_index = false — la ricerca funziona ancora (corrispondenza di parole intere contro il contenuto) ma le scansioni sono più lente; su un piccolo VPS dimezza il database. Consigliato su istanze piccole.
- disabled_fsync — scambia durabilità per throughput: le scritture vengono confermate nella page cache del SO e una perdita di alimentazione può perdere le scritture più recenti.
Sezione [daemon] — demone
| Chiave | Tipo | Predefinito | Descrizione |
|---|
pid_file | string | "./nostrfy.pid" | Percorso del file PID |
log_file | string | "./nostrfy.log" | Percorso del file di log |
stats_file | string | "./nostrfy.stats.json" | Percorso del file di statistiche |
stats_interval_secs | integer | 5 | Intervallo di scrittura delle statistiche (secondi) |
max_log_size_bytes | integer | 52428800 (50 MB) | Dimensione di rotazione del log (0 = nessuna rotazione) |
max_log_files | integer | 5 | Generazioni di log ruotati da conservare |
I percorsi sono risolti rispetto alla directory del file di configurazione, quindi restano validi dopo che il demone cambia la sua directory di lavoro.
Sezione [access] — controllo degli accessi
| Chiave | Tipo | Predefinito | Descrizione |
|---|
restrict_relay | boolean | false | Solo le pubkey in allowlist possono pubblicare |
blocked_kinds | array of integers | [] | Kind da rifiutare |
allowed_kinds | array of integers | [] | Allowlist di kind; solo questi kind sono accettati quando non è vuota |
blocked_ips | array of strings | [] | Indirizzi IP rifiutati al momento della connessione |
method_grants | table: pubkey → array of strings | {} | Concessioni di metodi NIP-86 per pubkey non admin (gestite a runtime con assignmethod) |
Gli elenchi allow/deny delle pubkey non sono chiavi di configurazione — vivono nel database del relay (LMDB) e sono gestiti a runtime:
nostrfy relay allow npub1...
nostrfy relay deny npub1...
nostrfy relay list
- restrict_relay = true — solo le pubkey in allowlist possono pubblicare, mentre la lettura resta aperta a tutti (qualsiasi client può ancora sottoscrivere e recuperare dati).
- Una pubkey negata viene sempre rifiutata in pubblicazione e mai servita in lettura.
- method_grants — concessioni di metodi NIP-86 per pubkey non admin (pubkey → nomi di metodo, es. un moderatore con
banevent e listbannedevents). Inizializzate dalla configurazione alla prima esecuzione, poi gestite a runtime con assignmethod/unassignmethod di NIP-86 (ispezionate con listmethodassignees). Solo i metodi di moderazione e lettura sono delegabili — la gestione di permessi, ruoli, inviti e identità del relay resta solo admin, e una pubkey bannata viene rifiutata anche con concessioni. Vedi l'API di gestione.
Sezione [blossom] — server di file Blossom
| Chiave | Tipo | Predefinito | Descrizione |
|---|
host | string | "" | Hostname per il server Blossom (vuoto = disabilitato) |
storage | string | "local" | Backend: "local" (local_path) o "s3" (bucket compatibile S3) |
local_path | string | "/var/lib/nostrfy/images" | Radice di archiviazione locale per file multimediali |
max_upload_bytes | integer | 20971520 (20 MB) | Dimensione massima del file multimediale |
min_free_bytes | integer | 33554432 (32 MB) | Spazio su disco sotto il quale gli upload vengono rifiutati |
s3_endpoint | string | "" | Endpoint compatibile S3 (es. R2) |
s3_region | string | "" | Regione S3 (R2 usa "auto") |
s3_bucket | string | "" | Nome del bucket S3 |
s3_access_key | string | "" | Chiave di accesso S3 |
s3_secret_key | string | "" | Chiave segreta S3 |
restrict_uploads | boolean | false | Solo le pubkey in allowlist possono caricare file |
Ricarica a runtime (SIGHUP)
Modificare il file e inviare kill -HUP $(cat nostrfy.pid) ricarica la configurazione senza riavvio. La maggior parte delle impostazioni ha effetto immediato; alcune sono fisse all’avvio:
| Si applica con SIGHUP | Richiede riavvio |
|---|
| 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 |
| la maggior parte di [limits] | api_host, trusted_proxies, metrics_enabled, ws_paths, database.*, dimensioni del demone, tetti dei limiti, blossom.* |
[access] non viene applicato da una ricarica — gli elenchi vengono inizializzati una volta all’avvio e poi gestiti a runtime via NIP-86. Il log avvisa quando cambia un’impostazione che richiede il riavvio, e alcune impostazioni acquisite all’avvio non sono verificate dalla ricarica.
| Errore | Soluzione |
|---|
| public_url non impostato | imposta wss://... |
| host lasciato a 127.0.0.1 | i client esterni non possono connettersi |
| private_key non impostata con NIP-29 | esegui nostrfy genkey + riavvia |
| restrict_relay true con allowlist vuota | tutti bloccati |
| modificare chiavi solo-riavvio e fare solo SIGHUP | usa nostrfy restart |