File server Blossom
Hosting multimediale sul proprio hostname: upload indirizzati per contenuto, storage locale o compatibile S3 e autenticazione kind-24242 per il tuo relay Nostr.
Panoramica
nostrfy può fungere da server blob Blossom: i client caricano file indirizzati tramite il loro hash SHA-256, e il relay li restituisce. Come l’API REST, vive su un hostname dedicato sulla stessa porta.
Configurazione
[blossom]
host = "media.example.com" # obbligatorio — abilita la funzione
storage = "local" # "local" o "s3"
local_path = "./data/images" # radice dello storage locale
max_upload_bytes = 20971520 # 20 MiB
min_free_bytes = 33554432 # rifiuta gli upload quando il disco ha poco spazio libero
restrict_uploads = false # solo le pubkey nella allowlist possono caricare
# Per S3 / Cloudflare R2:
s3_endpoint = "https://<account>.r2.cloudflarestorage.com"
s3_region = "auto"
s3_bucket = "nostr-media"
s3_access_key = "..."
s3_secret_key = "..."Indirizza media.example.com alla stessa porta nel tuo reverse proxy, poi riavvia. GET /
su quell’host risponde con il documento informativo del server Blossom. Con storage = "s3" l’endpoint deve essere HTTPS a meno che l’host sia loopback (p. es. un MinIO locale per i test).
Layout dello storage
Entrambi i backend usano la gerarchia <npub1...>, indicizzata dallo SHA-256 del file:
- local — file sotto
<local_path>/<npub1...>/<sha256> - s3 / R2 — oggetti
<npub1...>/<sha256>nel bucket configurato
I byte dei blob non toccano mai il database del relay — LMDB contiene solo la mappatura sha256 → proprietario e la allowlist degli upload.
Endpoint
| Metodo | Percorso | Auth | Descrizione |
|---|---|---|---|
GET | / | — | Informazioni sul server Blossom |
GET / HEAD | /<sha256>[.ext] | — | Recupero / verifica di un blob (intervalli di byte, 206) |
PUT | /upload | kind 24242 (t=upload, x=sha256, expiration) | Caricamento di un blob — 201 nuovo, 200 già esistente |
HEAD | /upload | kind 24242 (t=upload, x=sha256, expiration) | Controllo preliminare BUD-06 — l’upload verrebbe accettato? |
PUT | /media | kind 24242 (t=media, x=sha256, expiration) | Upload multimediale BUD-05 (memorizzato così com’è) |
HEAD | /media | kind 24242 (t=media, x=sha256, expiration) | Controllo preliminare BUD-05 — l’upload verrebbe accettato? |
GET | /list/<pubkey> | kind 24242 (t=list, expiration) | Blob caricati dalla pubkey richiedente (cursore + limit) |
DELETE | /<sha256> | kind 24242 (t=delete, x=sha256, expiration) | Eliminazione di un blob (solo chi l’ha caricato) |
Note di sicurezza
- I byte caricati dagli utenti sono serviti con
X-Content-Type-Options: nosniff. - HTML/SVG/XML/JavaScript ricevono inoltre
Content-Disposition: attachmente una CSP sandbox, così l’origine multimediale non può essere usata per XSS persistente. - I token sono accettati sia nella forma base64url della specifica (senza padding) sia nella forma standard con padding (BUD-11).
- L’header
X-SHA-256è verificato rispetto ai byte reali — una mancata corrispondenza restituisce 409. - I file sono serviti con ETag, Cache-Control: immutable e il content type memorizzato.
- Una pubkey bannata con NIP-86
banpubkeyè rifiutata su ogni endpoint.
Esempio
# Info sul server
curl https://media.example.com/
# Upload (evento di autenticazione dal tuo client Blossom, ad es. tramite nak o l'helper blossom di nostr-tools)
curl -X PUT -H "Authorization: Nostr <auth>" -H "Content-Type: image/png" --data-binary @photo.png https://media.example.com/upload
# Recupero
curl https://media.example.com/<sha256>
# Elenca i tuoi upload (evento di autenticazione con t=list; la pubkey nel percorso deve essere la tua)
curl -H "Authorization: Nostr <auth>" https://media.example.com/list/<pubkey-hex>
# Elimina (evento di autenticazione con t=delete e x=<sha256>)
curl -X DELETE -H "Authorization: Nostr <auth>" https://media.example.com/<sha256>Limitare gli upload
Imposta restrict_uploads = true nella sezione [blossom]:
[blossom]
host = "media.example.com"
restrict_uploads = trueLa allowlist vive nel database del relay (LMDB), gestita con comandi dedicati — nessun riavvio necessario, il demone ricarica automaticamente:
nostrfy blossom allow npub1... # autorizza una pubkey (npub1... o hex)
nostrfy blossom deny npub1... # revoca una pubkey
nostrfy blossom list # mostra la lista e restrict_uploadsGli upload da pubkey non in lista sono rifiutati con 403.
Backup e migrazione
Esegui il backup sia dello storage blob configurato sia di database.path per preservare l’inventario completo
e lo stato di autorizzazione. La mappatura sha256 → proprietario è persistita in LMDB, quindi i riavvii sono
istantanei e non servono indici in memoria né scansioni all’avvio — le ricerche leggono la mappatura direttamente dal
database. Una migrazione automatica una tantum ricostruisce la mappatura dai blob legacy al primo
avvio dopo un aggiornamento; un marcatore salta i riavvii successivi.