Decentralized blob storage server with Nostr integration, supporting multiple protocols and advanced media processing capabilities.
- NIP-96 - Nostr file storage with media processing
- Blossom Protocol - Complete BUD specification compliance:
- Image & Video Compression - Automatic WebP conversion and optimization
- Thumbnail Generation - Auto-generated thumbnails for images and videos
- Blurhash Calculation - Progressive image loading with blur previews
- AI Content Labeling - Automated tagging using configurable HuggingFace ViT models
- Media Metadata - Automatic extraction of dimensions, duration, bitrate
- Range Request Support - RFC 7233 compliant partial content delivery
- Automated Flagging - Files are automatically flagged (
LabelFlagged) when AI labels match configured terms - User Reports - Community-driven reporting via NIP-56; flagged files get
Reportedstate - Review Queue - Admin API to list all files pending review (
LabelFlaggedorReported) - Admin Actions - Mark files as reviewed or hard-delete them directly from the queue
- Background Labeling - Retroactively labels existing uploads that were missed at upload time
- Nostr Authentication - Cryptographic identity with kind 24242 events
- Whitelist Support - Restrict uploads to approved public keys
- Quota Management - Per-user storage limits with payment integration
- Admin Dashboard - Web interface for content and user management
- CORS Support - Full cross-origin resource sharing compliance
- EXIF Privacy Protection - Optional rejection of images with sensitive metadata (GPS, device info)
- Lightning Network - Bitcoin payments via LND integration
- Fiat Tracking - Multi-currency support (USD/EUR/GBP/JPY/etc.)
- Flexible Billing - Usage-based pricing (storage, egress, time-based)
- Free Quotas - Configurable free tier for new users
- Plausible Integration - Privacy-focused usage analytics
- Comprehensive Logging - Detailed operation tracking with per-label confidence scores
GET /<sha256>- Retrieve blob by hashHEAD /<sha256>- Check blob existencePUT /<sha256>- Upload a blob using its lowercase SHA-256 path (BUD-13)PUT /upload- Legacy-compatible blob uploadDELETE /<sha256>- Delete owned blobGET /list/<pubkey>- List user's blobsPUT /mirror- Mirror blob from remote URLPUT /media- Upload with media optimizationHEAD /upload- Validate upload requirementsPUT /report- Submit content reports
GET /.well-known/nostr/nip96.json- Server informationPOST /nip96- File upload with Nostr authDELETE /nip96/<sha256>- Delete with Nostr auth
GET /admin/self- Current user info and quotaGET /admin/files- List all files (paginated, filterable by MIME type)GET /admin/files/review- List files pending moderation reviewPATCH /admin/files/review- Mark files as reviewed (batch, JSON body)DELETE /admin/files/review- Ban and delete files from disk (batch, JSON body)GET /admin/files/<sha256>/similar- Find visually similar images (pHash + LSH)GET /admin/reports- List unreviewed user reportsDELETE /admin/reports- Acknowledge reports (batch, JSON body)GET /admin/user/<pubkey>- User info, files, and payment historyDELETE /admin/user/<pubkey>/purge- Delete all files belonging to a userGET /docs.md- Admin API reference (embedded Markdown)
Route96 uses YAML configuration. See config.yaml for a complete example.
listen: "127.0.0.1:8000"
database: "mysql://user:pass@localhost:3306/route96"
storage_dir: "./data"
max_upload_bytes: 104857600 # 100MB
public_url: "https://your-domain.com"cold_storage_dir: "/mnt/hdd/route96" # slow storage, read at startup
cold_storage_min_downloads: 50 # default 50
cold_storage_after_days: 7 # default 7A background task moves files older than cold_storage_after_days with fewer than
cold_storage_min_downloads downloads (egress bytes / size) from storage_dir to
cold_storage_dir, and moves cold files back once they reach the threshold. Both
thresholds can be changed from the admin config page. Files are copied, hash checked,
then removed from the source, and are served from whichever tier holds them.
# Directory where HuggingFace model files are cached (default: <storage_dir>/models)
models_dir: "./data/models"
# Models to run on every upload. Files are downloaded from HuggingFace on first use.
label_models:
- hf_repo: "google/vit-base-patch16-224"
name: "vit224"
- hf_repo: "v0l/route96-nsfw-vit224"
name: "nsfw"
label_exclude:
- "normal" # suppress the "clean" class from the NSFW model
# Labels containing any of these terms (case-insensitive substring) will be
# automatically flagged for admin review.
label_flag_terms:
- "nsfw"
- "explicit"
- "porn"
- "sexy"
- "hentai"Models are downloaded once and cached under models_dir/<org>--<repo>/. A background
task runs at startup to retroactively label any existing uploads that are missing labels.
payments:
free_quota_bytes: 104857600 # 100 MB free tier
fiat: "USD"
lnd:
endpoint: "https://127.0.0.1:10001"
tls: "/path/to/tls.cert"
macaroon: "/path/to/admin.macaroon"
cost:
currency: "BTC"
amount: 0.00000100
unit: "GBSpace"
interval:
month: 1sha256=$(sha256sum image.jpg | cut -d' ' -f1)
auth_event='{"kind":24242,"tags":[["t","upload"],["x","'$sha256'"],["expiration","1234567890"]],"content":"Upload file"}'
auth_b64=$(echo $auth_event | base64 -w 0)
curl -X PUT "http://localhost:8000/$sha256" \
-H "Authorization: Nostr $auth_b64" \
-H "Content-Type: image/jpeg" \
--data-binary @image.jpgcurl http://localhost:8000/abc123def456...789# List files pending review
curl -H "Authorization: Nostr $auth_b64" \
http://localhost:8000/admin/files/review
# Mark a file as reviewed
curl -X PATCH -H "Authorization: Nostr $auth_b64" \
http://localhost:8000/admin/files/<sha256>/review
# Delete a flagged file
curl -X DELETE -H "Authorization: Nostr $auth_b64" \
http://localhost:8000/admin/files/<sha256>/review| Flag | Default | Description |
|---|---|---|
nip96 |
on | NIP-96 protocol support |
blossom |
on | Blossom protocol support |
media-compression |
off | WebP conversion, thumbnails, media metadata |
labels |
on | AI content labeling (requires media-compression) |
cuda |
off | Run label models on GPU via CUDA (implies labels) |
payments |
off | Lightning payment integration |
analytics |
on | Plausible analytics |
react-ui |
on | Web dashboard interface |
r96util |
on | CLI utility binary for maintenance operations |
# CPU labeling
cargo build --features "blossom,media-compression,labels"
# GPU labeling
cargo build --features "blossom,media-compression,cuda"- Rust 1.70+
- MySQL/MariaDB - Database storage
- FFmpeg libraries - Media processing (
media-compression/labelsfeatures) - Node.js - UI building (optional)
See docs/debian.md for detailed installation instructions.
docker compose -f docker-compose.prod.yml updocker run --rm -it \
-p 8000:8000 \
-v ./config.yaml:/app/config.yaml \
-e "RUST_LOG=info" \
voidic/route96See docs/debian.md