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
[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
| Methode | Pfad | Auth | Beschreibung |
|---|---|---|---|
GET | / | — | Blossom-Serverinfo |
GET / HEAD | /<sha256>[.ext] | — | Blob abrufen / prüfen (Byte-Ranges, 206) |
PUT | /upload | kind 24242 (t=upload, x=sha256, expiration) | Blob hochladen — 201 neu, 200 existiert bereits |
HEAD | /upload | kind 24242 (t=upload, x=sha256, expiration) | BUD-06-Pre-Flight — würde der Upload akzeptiert? |
PUT | /media | kind 24242 (t=media, x=sha256, expiration) | BUD-05-Medienupload (unverändert gespeichert) |
HEAD | /media | kind 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: nosniffausgeliefert. - HTML/SVG/XML/JavaScript erhalten zusätzlich
Content-Disposition: attachmentund 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
banpubkeygebannter Pubkey wird auf jedem Endpunkt abgewiesen.
Beispiel
# 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]:
[blossom]
host = "media.example.com"
restrict_uploads = trueDie Allowlist liegt in der Relay-Datenbank (LMDB) und wird mit eigenen Befehlen verwaltet — kein Neustart nötig, der Daemon lädt automatisch neu:
nostrfy blossom allow npub1... # Pubkey freigeben (npub1... oder hex)
nostrfy blossom deny npub1... # Pubkey entziehen
nostrfy blossom list # Liste und restrict_uploads anzeigenUploads 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.