Bases
La configuration est un fichier TOML, par
défaut nommé nostrfy.toml. Créez-le avec init :
nostrfy --config nostrfy.toml init
Validez-le (recommandé avant chaque démarrage) :
nostrfy --config nostrfy.toml check
Chaque commande accepte --config <path> (par défaut nostrfy.toml).
Syntaxe générale :
[section]
key = "string"
key = 8080
key = [1, 2]
key = true
Sections de configuration
| Section | Objet |
|---|
[relay] | Identité, URLs et interrupteurs NIP |
[server] | Liaison réseau, séparation API, métriques |
[rpc] | RPC de gestion NIP-86 (auth, limite de corps) |
[limits] | Toutes les limites et protections contre la surcharge |
[database] | Stockage LMDB, index de recherche, plafonds de file |
[daemon] | Fichiers PID, journal et statistiques, et rotation |
[access] | Listes de contrôle d’accès initiales (modifiables à l’exécution) |
[blossom] | Serveur de fichiers Blossom (hébergement média) |
Chaque clé est optionnelle ; une clé manquante utilise sa valeur par défaut.
Section [relay] — identité du relais
| Clé | Type | Défaut | Description |
|---|
name | string | "nostrfy" | Nom du relais affiché aux clients via NIP-11 |
description | string | "A minimal and stable Nostr relay" | Description du relais (NIP-11) |
pubkey | string (64 hex) | "" | Clé publique de l’administrateur (champ pubkey NIP-11) |
contact | string | "" | URI de contact de l’administrateur (mailto: ou https://) |
icon | string | "" | URL de l’image d’icône du relais |
post_policy | string | "" | URL pointant vers la politique de publication du relais |
private_key | string (64 hex) | "" | Clé secrète propre au relais ; requise pour les groupes NIP-29 |
public_url | string | "" | URL publique, p. ex. wss://relay.example.com |
livekit_url | string | "" | URL du serveur LiveKit pour les salons audio/vidéo NIP-29 |
livekit_api_key | string | "" | Clé API LiveKit |
livekit_api_secret | string | "" | Secret API LiveKit (utilisé pour signer les JWT) |
enabled_nips | array of integers | [] | Liste d’autorisation NIP explicite |
disabled_nips | array of integers | [] | NIPs à désactiver (ignoré quand enabled_nips est non vide) |
reject_ephemeral | boolean | false | Rejeter les événements éphémères NIP-01 (kinds 20000–29999) |
enabled_git | boolean | false | Accepter les événements git NIP-34 (kinds 1617–1633, 30617/30618) |
require_pow | integer | 0 | Preuve de travail requise en bits zéro initiaux |
new_pubkey_min_age_secs | integer | 0 | Refuser les événements des pubkeys plus jeunes que cette valeur (secondes ; 0 = désactivé) |
max_events_per_min_per_pubkey | integer | 0 | Limite de débit de publication par pubkey (par minute ; 0 = sans limite) |
max_groups | integer | 1000 | Plafond du magasin de groupes NIP-29 en mémoire |
require_auth | boolean | false | Exiger l’authentification NIP-42 pour REQ/EVENT/COUNT/NEG |
send_auth_challenge | boolean | true | Envoyer le défi AUTH à la connexion |
enabled_nip78_auth | boolean | true | Exiger AUTH NIP-42 avant d’accepter les événements kind 78/30078 |
enabled_command_events | boolean | false | Exécuter les commandes opérateur kind:1 rédigées par la pubkey admin |
Détails des clés
- private_key — clé secrète propre au relais, utilisée pour signer les événements générés par le relais : métadonnées
de groupes NIP-29 (39000–39005) et événements de rôles/membres NIP-43. Générez-la avec
nostrfy genkey ; gardez-la
secrète. Elle est lue une fois au démarrage, donc toute modification exige un redémarrage. - public_url — utilisée pour valider les tags porteurs d’URL des clients : AUTH NIP-42, vanish NIP-62 et
auth admin NIP-98. Quand elle est vide, le relais se replie sur
host:port, qui ne correspond jamais à une vraie
URL client lors de la liaison à 0.0.0.0 ou 127.0.0.1 (un avertissement est journalisé). Définissez-la toujours. - enabled_nips vs disabled_nips — la liste d’autorisation l’emporte : quand
enabled_nips est
non vide, seuls ses NIPs sont annoncés et disabled_nips est ignoré. Les deux exigent un redémarrage. - reject_ephemeral — les kinds 20000–29999 sont rejetés, mais les kinds exemptés que les NIPs exigent de
relayer sont toujours transmis : 22242, 27235, 28934/28935/28936, 24133, 23194/23195, 24242 et 21059. S’applique sur SIGHUP.
- enabled_git — opt-in NIP-34 : accepte les kinds 1617–1633 et 30617/30618 et annonce NIP-34.
Désactivé par défaut car les charges de patch peuvent être volumineuses. S’applique sur SIGHUP.
Section [server] — paramètres serveur
| Clé | Type | Défaut | Description |
|---|
host | string | "127.0.0.1" | Adresse de liaison ; 0.0.0.0 accepte les connexions de partout |
port | integer | 8080 | Port (1–65535) ; le port 80 exige root |
api_host | string | "" | Nom d’hôte dédié à l’API REST |
metrics_enabled | boolean | true | Servir les métriques Prometheus sur /metrics |
ws_paths | string | "root" | Chemins des points de terminaison WebSocket : root, inbox-outbox ou all |
inbox_write_policy | string | "any" | Qui peut écrire sur /inbox : « any » ou « relay » (les événements doivent toujours porter un tag p) |
outbox_write_policy | string | "any" | Qui peut écrire sur /outbox : « any » (propres événements de la pubkey authentifiée NIP-42) ou « relay » |
trusted_proxies | array of strings | [] | Adresses/CIDRs de reverse-proxy dont le X-Forwarded-For est de confiance (vide = aucun proxy de confiance) |
Détails des clés
- host —
0.0.0.0 lie toutes les interfaces IPv4 ; 127.0.0.1 est local uniquement. - port — 1–65535 ; le port 80 exige root. Ce port unique sert ensemble le relais WebSocket, le document NIP-11, l’API REST et le RPC NIP-86.
- api_host — dédie l’API REST à un seul nom d’hôte pour que l’API et le relais puissent partager un
port derrière un reverse-proxy. Figé au démarrage — exige un redémarrage.
- ws_paths —
root sert uniquement /, inbox-outbox sert uniquement /inbox et
/outbox, all sert les deux. Figé au démarrage — exige un redémarrage. - trusted_proxies — listez uniquement les propres adresses du proxy (loopback pour nginx/Caddy sur le même
hôte, plage source de l’équilibreur dans le cloud). Si défini, l’IP client est dérivée de la dernière entrée
X-Forwarded-For non de confiance pour les plafonds par IP, la limite de débit, blockip et les logs. N’ajoutez jamais
une adresse joignable directement par les clients — ils pourraient falsifier l’en-tête et contourner les limites par IP.
Figé au démarrage — exige un redémarrage.
Section [rpc] — gestion NIP-86
| Clé | Type | Défaut | Description |
|---|
management_token | string | "" | Jeton Bearer pour les API de gestion |
admin_pubkey | string (64 hex) | "" | Pubkey administrateur pour l’auth de gestion NIP-98 |
max_admin_body_bytes | integer | 65536 | Limite de corps pour le RPC de gestion NIP-86 |
Le RPC NIP-86 est monté sur les routes publiques POST / du relais — il n’y a pas de port de gestion séparé. management_token et admin_pubkey apparaissent parfois sous [server] dans les anciens guides ; ces orthographes sont des alias historiques de ces clés [rpc].
Section [limits] — limites et protections
Connexions et messages
| Clé | Type | Défaut | Description |
|---|
max_connections | integer | 10000 | Connexions simultanées maximales |
max_connections_per_ip | integer | 64 | Max. de connexions par IP source |
max_ws_message_bytes | integer | 1048576 | Max. d’octets par message/frame WebSocket |
socket_recv_buffer_kb | integer | 64 | Tampon de réception noyau par connexion (Kio) |
max_out_queue_bytes | integer | 262144 | Plafond de file sortante par connexion (octets) |
ws_idle_timeout_secs | integer | 300 | Fermer les connexions inactives après ce délai |
http_read_timeout_secs | integer | 30 | Délai d’en-tête de requête HTTP (défense slow-loris) |
max_connections_per_sec_per_ip | integer | 0 | Max. de nouvelles connexions par seconde par IP source |
Abonnements et requêtes
| Clé | Type | Défaut | Description |
|---|
max_filters | integer | 20 | Max. de filtres par REQ |
max_subscriptions | integer | 20 | Max. d’abonnements par connexion |
max_limit | integer | 500 | Plafond pour la limite REQ |
max_count | integer | 2000 | Plafond pour les résultats COUNT |
max_sub_id_len | integer | 64 | Longueur max. d’id d’abonnement (caractères, pas octets) |
max_sub_bytes | integer | 1048576 | Total d’octets de filtres d’abonnement par connexion |
max_req_response_bytes | integer | 33554432 (32 Mo) | Plafond pour le total d’octets qu’une seule réponse REQ peut envoyer |
Événements
| Clé | Type | Défaut | Description |
|---|
max_content_bytes | integer | 65536 | Longueur max. du contenu d’événement en caractères |
max_tags | integer | 2000 | Max. de tags par événement |
max_tag_value_bytes | integer | 1024 | Max. d’octets par valeur de tag |
max_created_at_future_secs | integer | 3600 | Écart futur toléré de created_at |
group_late_publish_secs | integer | 3600 | Retard toléré pour les événements admin de groupes NIP-29 (secondes) |
max_neg_items | integer | 100000 | Max. d’enregistrements par synchronisation negentropy NIP-77 |
Alias historiques : limits.require_pow, limits.new_pubkey_min_age_secs et limits.max_indexed_words sont toujours acceptés comme alias de relay.require_pow, relay.new_pubkey_min_age_secs et database.max_indexed_words.
API REST
| Clé | Type | Défaut | Description |
|---|
max_api_concurrent | integer | 8 | Max. de requêtes /api/v1 simultanées |
max_api_limit | integer | 5000 | Plafond pour le paramètre limit de l’API |
max_api_offset | integer | 50000 | Plafond pour le paramètre offset de l’API |
max_api_fetch | integer | 55001 | Fenêtre de sur-récupération max. pour les requêtes offset — doit couvrir max_api_offset + max_api_limit + 1 (0 = sans borne) |
max_api_search_bytes | integer | 2048 | Max. d’octets du paramètre search de l’API |
Diffusion live
| Clé | Type | Défaut | Description |
|---|
live_batch_interval_ms | integer | 20 | Fréquence de vidage des événements live (ms) |
live_batch_size | integer | 32 | Max. d’événements par lot live |
live_buffer | integer | 65536 | Taille de la file de diffusion live |
Section [database] — base de données
| Clé | Type | Défaut | Description |
|---|
path | string | "./data" | Répertoire de la base de données (LMDB) |
max_dbs | integer | 32 | Max. de bases nommées LMDB |
max_readers | integer | 128 | Max. de lecteurs simultanés LMDB |
map_size | integer | 1073741824 (1 Go) | Plancher pour la taille du memory map (octets) |
max_map_size | integer | 1099511627776 (1 TB) | Plafond du memory-map (octets) |
purge_interval_secs | integer | 300 | Intervalle de purge NIP-40 (secondes) |
search_index | boolean | true | Activer l’index de mots NIP-50 |
reader_threads | integer | 2 | Threads de scan dédiés |
max_indexed_words | integer | 32 | Mots du contenu de chaque événement indexés pour la recherche |
meta_index | boolean | true | Écrire l’en-tête de métadonnées par événement utilisé par le préfiltre de scan |
disabled_fsync | boolean | false | Ignorer le vidage disque synchrone après chaque lot d’écriture |
db_buffer_size | integer | 2048 | Tampon WebSocket initial par connexion (octets) |
db_request_timeout_secs | integer | 30 | Durée d’attente possible d’une requête base avant échec |
max_db_queue_msgs | integer | 4096 | Max. de messages en attente avant échec rapide |
max_db_queue_events | integer | 262144 | Max. d’événements dans les lots en attente avant échec rapide |
max_db_queue_bytes | integer | 268435456 (256 MiB) | Max. d’octets de requêtes base en file avant échec rapide (0 = sans plafond d’octets) |
Détails des clés
- map_size — le plancher pour le memory map : la map est toujours ouverte au moins à cette taille.
- max_map_size — le plafond, ouvert comme réservation virtuelle éparse : le disque physique ne croît qu’avec
les données réellement écrites. Augmentez-le en cas de
database map is full. - search_index = false — la recherche fonctionne toujours (correspondance de mots entiers dans le contenu) mais les scans
sont plus lents ; sur un petit VPS cela divise la base par deux. Recommandé sur les petites instances.
- disabled_fsync — échange la durabilité contre le débit : les écritures sont validées dans le cache de pages OS et
une coupure de courant peut perdre les écritures les plus récentes.
Section [daemon] — démon
| Clé | Type | Défaut | Description |
|---|
pid_file | string | "./nostrfy.pid" | Chemin du fichier PID |
log_file | string | "./nostrfy.log" | Chemin du fichier log |
stats_file | string | "./nostrfy.stats.json" | Chemin du fichier de statistiques |
stats_interval_secs | integer | 5 | Intervalle d’écriture des statistiques (secondes) |
max_log_size_bytes | integer | 52428800 (50 Mo) | Taille de rotation des logs (0 = sans rotation) |
max_log_files | integer | 5 | Générations de logs pivotés à conserver |
Les chemins sont résolus par rapport au répertoire du fichier de configuration, donc ils restent valides après que le démon change son répertoire de travail.
Section [access] — contrôle d’accès
| Clé | Type | Défaut | Description |
|---|
restrict_relay | boolean | false | Seules les pubkeys autorisées peuvent publier |
blocked_kinds | array of integers | [] | Kinds à rejeter |
allowed_kinds | array of integers | [] | Liste d’autorisation de kinds ; seuls ces kinds sont acceptés quand elle est non vide |
blocked_ips | array of strings | [] | Adresses IP refusées au moment de la connexion |
method_grants | table: pubkey → array of strings | {} | Octrois de méthodes NIP-86 pour les pubkeys non-admin (gérés à l’exécution avec assignmethod) |
Les listes d’autorisation/refus de pubkeys ne sont pas des clés de config — elles vivent dans la base du relais (LMDB) et sont
gérées à l’exécution :
nostrfy relay allow npub1...
nostrfy relay deny npub1...
nostrfy relay list
- restrict_relay = true — seules les pubkeys autorisées peuvent publier, tandis que
la lecture reste ouverte à tous (tout client peut toujours s’abonner et récupérer).
- Une pubkey refusée est toujours rejetée à la publication et jamais servie à la lecture.
- method_grants — octrois de méthodes NIP-86 pour les pubkeys non-admin (pubkey → noms de méthodes, p. ex. un
modérateur autorisé avec
banevent et listbannedevents). Initialisés depuis la config au
premier lancement, puis gérés à l’exécution avec NIP-86 assignmethod/unassignmethod (inspectés avec listmethodassignees). Seules les méthodes de modération et de lecture sont octroyables —
la gestion des permissions, rôles, revendications d’invitation et identité du relais reste réservée à l’admin, et une pubkey bannie est
refusée même avec des octrois. Voir l' API de gestion.
Section [blossom] — serveur de fichiers Blossom
| Clé | Type | Défaut | Description |
|---|
host | string | "" | Nom d’hôte pour le serveur Blossom (vide = désactivé) |
storage | string | "local" | Backend : « local » (local_path) ou « s3 » (bucket compatible S3) |
local_path | string | "/var/lib/nostrfy/images" | Racine de stockage local pour les fichiers média |
max_upload_bytes | integer | 20971520 (20 Mo) | Taille max. de fichier média |
min_free_bytes | integer | 33554432 (32 Mo) | Espace disque sous lequel les téléversements sont refusés |
s3_endpoint | string | "" | Point de terminaison compatible S3 (p. ex. R2) |
s3_region | string | "" | Région S3 (R2 utilise « auto ») |
s3_bucket | string | "" | Nom du bucket S3 |
s3_access_key | string | "" | Clé d’accès S3 |
s3_secret_key | string | "" | Clé secrète S3 |
restrict_uploads | boolean | false | Seules les pubkeys autorisées peuvent téléverser |
Rechargement à l’exécution (SIGHUP)
Modifier le fichier et envoyer kill -HUP $(cat nostrfy.pid) recharge la configuration sans
redémarrage. La plupart des réglages prennent effet immédiatement ; quelques-uns sont figés au démarrage :
| S’applique sur SIGHUP | Exige un redémarrage |
|---|
| 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 plupart des limites | api_host, trusted_proxies, metrics_enabled, ws_paths, database.*, tailles du démon, plafonds de limites, blossom.* |
[access] n’est pas appliqué par un rechargement — les listes sont initialisées une fois au démarrage puis gérées à l’exécution via NIP-86.
Le log avertit quand un réglage exigeant un redémarrage a changé, et quelques réglages capturés au démarrage ne sont pas vérifiés par le
rechargement.
| Erreur | Correctif |
|---|
| public_url non défini | définissez wss://... |
| host laissé à 127.0.0.1 | les clients externes ne peuvent pas se connecter |
| private_key non définie avec NIP-29 | exécutez nostrfy genkey + redémarrage |
| restrict_relay true avec allowlist vide | tout le monde est verrouillé |
| clés exigeant un redémarrage modifiées avec seulement un SIGHUP | utilisez nostrfy restart |