Blossom-Dateiserver

Medienhosting auf eigenem Hostnamen: inhaltsadressierte Uploads, lokaler oder S3-kompatibler Speicher und Kind-24242-Auth für Ihr Nostr-Relay.

Überblick

nostrfy kann als Blossom-Blob-Server agieren: Clients laden Dateien hoch, die über ihren SHA-256-Hash adressiert werden, und das Relay liefert sie wieder aus. Wie die REST-API lebt er auf einem eigenen Hostnamen auf demselben Port.

Konfiguration

toml
[blossom]
host = "media.example.com"          # erforderlich — aktiviert die Funktion
storage = "local"                   # "local" oder "s3"
local_path = "./data/images"        # lokales Speicherverzeichnis
max_upload_bytes = 20971520         # 20 MiB
min_free_bytes = 33554432           # Uploads ablehnen, wenn weniger freier Speicherplatz vorhanden ist
restrict_uploads = false            # nur Allowlist-Pubkeys dürfen hochladen

# Für S3 / Cloudflare R2:
s3_endpoint = "https://<account>.r2.cloudflarestorage.com"
s3_region = "auto"
s3_bucket = "nostr-media"
s3_access_key = "..."
s3_secret_key = "..."

Leiten Sie media.example.com in Ihrem Reverse-Proxy auf denselben Port und starten Sie neu. GET / auf diesem Host antwortet mit dem Blossom-Serverinfodokument. Mit storage = "s3" muss der Endpunkt HTTPS sein, es sei denn, der Host ist Loopback (z. B. ein lokales MinIO zum Testen).

Speicherlayout

Beide Backends verwenden die <npub1...>-Hierarchie mit der SHA-256 der Datei als Schlüssel:

  • local — Dateien unter <local_path>/<npub1...>/<sha256>
  • s3 / R2 — Objekte <npub1...>/<sha256> im konfigurierten Bucket

Blob-Bytes berühren nie die Relay-Datenbank — LMDB hält nur das sha256→Owner-Mapping und die Upload- Allowlist.

Endpunkte

MethodePfadAuthBeschreibung
GET/—Blossom-Serverinfo
GET / HEAD/<sha256>[.ext]—Blob abrufen / prüfen (Byte-Ranges, 206)
PUT/uploadkind 24242 (t=upload, x=sha256, expiration)Blob hochladen — 201 neu, 200 existiert bereits
HEAD/uploadkind 24242 (t=upload, x=sha256, expiration)BUD-06-Pre-Flight — würde der Upload akzeptiert?
PUT/mediakind 24242 (t=media, x=sha256, expiration)BUD-05-Medienupload (unverändert gespeichert)
HEAD/mediakind 24242 (t=media, x=sha256, expiration)BUD-05-Pre-Flight — würde der Upload akzeptiert?
GET/list/<pubkey>kind 24242 (t=list, expiration)Vom anfragenden Pubkey hochgeladene Blobs (Cursor + Limit)
DELETE/<sha256>kind 24242 (t=delete, x=sha256, expiration)Blob löschen (nur Uploader)

Sicherheitshinweise

  • Vom Nutzer hochgeladene Bytes werden mit X-Content-Type-Options: nosniff ausgeliefert.
  • HTML/SVG/XML/JavaScript erhalten zusätzlich Content-Disposition: attachment und ein Sandbox-CSP, sodass der Medien-Origin nicht für gespeichertes XSS genutzt werden kann.
  • Token werden sowohl in der Base64url-Form der Spezifikation (ohne Padding) als auch in der gepaddeten Standardform akzeptiert (BUD-11).
  • Der X-SHA-256-Header wird gegen die tatsächlichen Bytes geprüft — bei Abweichung folgt 409.
  • Dateien werden mit ETag, Cache-Control: immutable und dem gespeicherten Inhaltstyp ausgeliefert.
  • Ein per NIP-86 banpubkey gebannter Pubkey wird auf jedem Endpunkt abgewiesen.

Beispiel

sh
# Serverinfo
curl https://media.example.com/

# Upload (Auth-Event Ihres Blossom-Clients, z. B. via nak oder dem nostr-tools-Blossom-Helper)
curl -X PUT -H "Authorization: Nostr <auth>" -H "Content-Type: image/png" --data-binary @photo.png https://media.example.com/upload

# Abrufen
curl https://media.example.com/<sha256>

# Eigene Uploads auflisten (Auth-Event mit t=list; der Pubkey im Pfad muss Ihrer sein)
curl -H "Authorization: Nostr <auth>" https://media.example.com/list/<pubkey-hex>

# Löschen (Auth-Event mit t=delete und x=<sha256>)
curl -X DELETE -H "Authorization: Nostr <auth>" https://media.example.com/<sha256>

Uploads einschränken

Setzen Sie restrict_uploads = true im Abschnitt [blossom]:

toml
[blossom]
host = "media.example.com"
restrict_uploads = true

Die Allowlist liegt in der Relay-Datenbank (LMDB) und wird mit eigenen Befehlen verwaltet — kein Neustart nötig, der Daemon lädt automatisch neu:

sh
nostrfy blossom allow npub1...          # Pubkey freigeben (npub1... oder hex)
nostrfy blossom deny npub1...           # Pubkey entziehen
nostrfy blossom list                    # Liste und restrict_uploads anzeigen

Uploads von nicht gelisteten Pubkeys werden mit 403 abgelehnt.

Backups und Migration

Sichere sowohl den konfigurierten Blob-Speicher als auch database.path, um das vollständige Inventar und den Autorisierungszustand zu erhalten. Das sha256→Owner-Mapping liegt persistent in LMDB, daher sind Neustarts sofort und kein In-Memory-Index oder Startscan nötig — Lookups lesen das Mapping direkt aus der Datenbank. Eine automatische einmalige Migration baut das Mapping aus Legacy-Blobs beim ersten Start nach einem Upgrade neu auf; ein Marker überspringt spätere Neustarts.