Skip to main content

Blossom

Blobs Stored Simply on Mediaservers. Decentralized, censorship-resistant media hosting for Nostr.

Overview​

Blossom is a protocol for storing and retrieving binary data (images, videos, audio) across multiple servers. Using hash-based addressing and Nostr for authorization, Blossom ensures your media remains available even if individual servers go down.

How It Works​

┌─────────────────────────────────────────────────────────┐
│ Blossom Protocol │
├─────────────────────────────────────────────────────────┤
│ │
│ 1. Upload image to Blossom server │
│ ┌───────────────────────────────────────────────┐ │
│ │ image.jpg ──► SHA256 hash ──► Store blob │ │
│ │ Result: abc123... │ │
│ └───────────────────────────────────────────────┘ │
│ │
│ 2. Publish Nostr event with hash │
│ ┌───────────────────────────────────────────────┐ │
│ │ Event references: https://server.com/abc123 │ │
│ └───────────────────────────────────────────────┘ │
│ │
│ 3. Any client can fetch from any Blossom server │
│ ┌───────────────────────────────────────────────┐ │
│ │ Server A down? → Try Server B with same hash │ │
│ │ Same file, verified by hash │ │
│ └───────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘

Key Features​

Hash-Based Addressing​

Files are addressed by their SHA-256 hash:

┌─────────────────────────────────────────┐
│ File: photo.jpg │
│ Hash: a1b2c3d4e5f6... │
│ │
│ URL: https://blossom.server/a1b2c3d4 │
│ │
│ Any server with this hash = same file │
│ Hash verifies file integrity │
└─────────────────────────────────────────┘

Benefits:

  • Verification — Prove you got the right file
  • Deduplication — Same file, one hash
  • Server-agnostic — Get from any mirror

Mirroring​

┌─────────────────────────────────────────────────────────┐
│ Mirror Setup │
├─────────────────────────────────────────────────────────┤
│ │
│ Primary Server: blossom.example.com │
│ Mirrors: │
│ ├── blossom.nostr.build │
│ └── cdn.backup.com │
│ │
│ Upload Flow: │
│ File → Primary → Auto-mirror to backups │
│ │
│ Retrieval Flow: │
│ Primary down? → Try Mirror 1 → Try Mirror 2 │
│ │
│ Always available, always the same file │
│ │
└─────────────────────────────────────────────────────────┘

Nostr Integration​

Your Blossom settings are published to Nostr:

{
"kind": 10063,
"tags": [
["server", "https://blossom.primary.com", "primary"],
["server", "https://blossom.mirror.com", "mirror"]
],
"content": ""
}

Clients read your settings to know where to fetch your media.

Censorship Resistance​

ScenarioTraditional HostingBlossom
Server bans youContent goneUse another server
Server goes downContent unavailableMirrors still work
Regional blockCan't accessTry different server

BUD Specifications​

Blossom is defined by BUDs (Blossom Upgrade Documents):

BUDNameDescription
BUD-01Basic OperationsUpload, download, delete
BUD-02Blob DescriptorsMetadata for blobs
BUD-04MirroringAuto-copy to backups
BUD-05Media EndpointsStandard URLs
BUD-06HEAD RequestsCheck existence
BUD-08File MetadataExtended info

NIP-B7​

The Nostr Integration Proposal for Blossom:

{
"kind": 1,
"content": "Check out this image!",
"tags": [
["imeta",
"url https://blossom.server/abc123",
"x abc123...",
"m image/jpeg",
"dim 1920x1080",
"blurhash LKJHGF..."
]
]
}

Clients supporting NIP-B7:

  • Know the file hash
  • Can verify downloads
  • Can find mirrors if needed

Public Servers​

ServerProviderFeatures
blossom.nostr.buildnostr.buildGlobal CDN
blossom.primal.netPrimalDefault in Primal
Various self-hostedCommunityYour own control

Using nostr.build​

Upload: POST https://blossom.nostr.build/upload
Fetch: GET https://npub...blossom.nostr.build/hash

Each user gets their own subdomain for organization.

Client Support​

ClientBlossom Support
PrimalNative, default
noStrudelOptional, settings
AmethystSupported
CoracleSupported

Running Your Own​

Docker​

# docker-compose.yml
version: '3'
services:
blossom:
image: hzrd149/blossom:latest
ports:
- "3000:3000"
volumes:
- ./data:/app/data
environment:
PUBLIC_URL: https://blossom.yourdomain.com

Configuration​

{
"port": 3000,
"dataDir": "./data",
"maxUploadSize": 100000000,
"allowedMimeTypes": [
"image/*",
"video/*",
"audio/*"
]
}

Authorization​

Uploads require Nostr-signed auth events:

{
"kind": 24242,
"tags": [
["t", "upload"],
["size", "1234567"],
["x", "sha256hash"]
],
"content": ""
}

The signature proves you own the keypair, authorizing the upload.

Comparison​

FeatureBlossomIPFSTraditional CDN
AddressingHashHashURL
AuthorizationNostrNoneAPI keys
MirroringNativeP2PManual
Nostr integrationNativeNoneNone
Self-hostingEasyComplexComplex

Use Cases​

Social Media​

  • Profile pictures
  • Post images/videos
  • Media in DMs

Content Publishing​

  • Blog images
  • Podcast hosting
  • Video content

Backups​

  • Redundant storage
  • Personal archives
  • Distributed hosting

See Also​