Serveur de fichiers Blossom
Hébergement média sur son propre nom d’hôte : téléversements adressés par contenu, stockage local ou compatible S3, et authentification kind-24242 pour votre relais Nostr.
Aperçu
nostrfy peut agir comme serveur de blobs Blossom : les clients téléversent des fichiers adressés par leur hachage SHA-256, et le relais les ressert. Comme l’API REST, il vit sur un nom d’hôte dédié sur le même port.
Configuration
[blossom]
host = "media.example.com" # requis — active la fonctionnalité
storage = "local" # "local" ou "s3"
local_path = "./data/images" # racine du stockage local
max_upload_bytes = 20971520 # 20 MiB
min_free_bytes = 33554432 # refuse les téléversements quand l’espace disque libre est insuffisant
restrict_uploads = false # seules les clés de la liste d’autorisation peuvent téléverser
# Pour S3 / Cloudflare R2 :
s3_endpoint = "https://<account>.r2.cloudflarestorage.com"
s3_region = "auto"
s3_bucket = "nostr-media"
s3_access_key = "..."
s3_secret_key = "..."Pointez media.example.com vers le même port dans votre proxy inverse, puis redémarrez. GET /
sur cet hôte répond avec le document d’information du serveur Blossom. Avec storage = "s3",
le point de terminaison doit être en HTTPS sauf si l’hôte est loopback (p. ex. un MinIO local pour les tests).
Organisation du stockage
Les deux backends utilisent la hiérarchie <npub1...>, indexée par le SHA-256 du fichier :
- local — fichiers sous
<local_path>/<npub1...>/<sha256> - s3 / R2 — objets
<npub1...>/<sha256>dans le bucket configuré
Les octets des blobs ne touchent jamais la base de données du relais — LMDB ne contient que la correspondance sha256 → propriétaire et la liste d’autorisation de téléversement.
Points de terminaison
| Méthode | Chemin | Auth | Description |
|---|---|---|---|
GET | / | — | Informations du serveur Blossom |
GET / HEAD | /<sha256>[.ext] | — | Récupérer / sonder un blob (plages d’octets, 206) |
PUT | /upload | kind 24242 (t=upload, x=sha256, expiration) | Téléverser un blob — 201 nouveau, 200 existe déjà |
HEAD | /upload | kind 24242 (t=upload, x=sha256, expiration) | Pré-vol BUD-06 — le téléversement serait-il accepté ? |
PUT | /media | kind 24242 (t=media, x=sha256, expiration) | Téléversement média BUD-05 (stocké tel quel) |
HEAD | /media | kind 24242 (t=media, x=sha256, expiration) | Pré-vol BUD-05 — le téléversement serait-il accepté ? |
GET | /list/<pubkey> | kind 24242 (t=list, expiration) | Blobs téléversés par la clé publique demanderesse (curseur + limit) |
DELETE | /<sha256> | kind 24242 (t=delete, x=sha256, expiration) | Supprimer un blob (téléverseur uniquement) |
Notes de sécurité
- Les octets téléversés par les utilisateurs sont servis avec
X-Content-Type-Options: nosniff. - HTML/SVG/XML/JavaScript reçoivent en plus
Content-Disposition: attachmentet une CSP sandbox, de sorte que l’origine média ne peut pas servir au XSS stocké. - Les jetons sont acceptés sous la forme base64url de la spécification (sans padding) et sous la forme standard avec padding (BUD-11).
- L’en-tête
X-SHA-256est vérifié par rapport aux octets réels — une discordance renvoie 409. - Les fichiers sont servis avec ETag, Cache-Control: immutable et le type de contenu stocké.
- Une clé publique bannie via NIP-86
banpubkeyest refusée sur chaque point de terminaison.
Exemple
# Infos du serveur
curl https://media.example.com/
# Téléversement (événement d’authentification depuis votre client Blossom, par ex. via nak ou l’assistant blossom de nostr-tools)
curl -X PUT -H "Authorization: Nostr <auth>" -H "Content-Type: image/png" --data-binary @photo.png https://media.example.com/upload
# Récupération
curl https://media.example.com/<sha256>
# Listez vos propres téléversements (événement d’authentification avec t=list ; la clé du chemin doit être la vôtre)
curl -H "Authorization: Nostr <auth>" https://media.example.com/list/<pubkey-hex>
# Suppression (événement d’authentification avec t=delete et x=<sha256>)
curl -X DELETE -H "Authorization: Nostr <auth>" https://media.example.com/<sha256>Restreindre les téléversements
Définissez restrict_uploads = true dans la section [blossom] :
[blossom]
host = "media.example.com"
restrict_uploads = trueLa liste d’autorisation vit dans la base de données du relais (LMDB), gérée avec des commandes dédiées — aucun redémarrage requis, le démon recharge automatiquement :
nostrfy blossom allow npub1... # autorisez une clé (npub1... ou hex)
nostrfy blossom deny npub1... # révoquez une clé
nostrfy blossom list # affichez la liste et restrict_uploadsLes téléversements des clés publiques non listées sont rejetés avec 403.
Sauvegardes et migration
Sauvegardez à la fois le stockage de blobs configuré et database.path pour préserver l’inventaire complet
et l’état d’autorisation. La correspondance sha256 → propriétaire est persistée dans LMDB, donc les redémarrages sont
instantanés et aucun index en mémoire ni balayage au démarrage n’est nécessaire — les recherches lisent la correspondance directement depuis
la base de données. Une migration automatique unique reconstruit la correspondance à partir des blobs hérités au premier
démarrage après une mise à niveau ; un marqueur ignore les redémarrages suivants.