Iceberg / Asset CDN
Live · serving 6,219 assets from Cloudflare R2

This is where our images actually live.

Iceberg is a small, self-hosted CDN we run on top of Cloudflare R2. Every image used across katalyst-crm.com is stored here and served straight from Cloudflare's edge network — no per-GB bandwidth bill, no vendor lock-in.

6,219
Images stored
2.7GB
Total library
$0/GB
Egress

Quick start

Three ways to use Iceberg — pick the one that matches the work you're doing.

Drop the URL straight into any <img>, <video>, CSS background-image, or fetch — no auth required.

HTML
<img src="https://cdn.katalyst-crm.com/t1/cloudinary/sample.jpg" alt="…" />

Convert an existing Cloudinary URL: drop res.cloudinary.com/dcuswyfur/image/upload/<transforms>/v123/ and prepend cdn.katalyst-crm.com/t1/cloudinary/.

CLI reference

Every iceberg subcommand.

Command Purpose
iceberg loginAuthenticate and cache an API token at ~/.iceberg/config.json
iceberg whoamiShow the account behind the saved token
iceberg config showPrint saved url + token + tenant + cdn
iceberg config set --cdn XPin the public CDN base URL
iceberg upload <file> --key KPresigned PUT directly to R2; promotes catalog row to ready
iceberg ls --limit NList assets in your tenant
iceberg url <key>Print the public CDN URL for embedding
iceberg rm <key>Delete both the storage object and the catalog row
iceberg migrate cloudinaryBulk import from a Cloudinary account (dry-run by default)

How it's built

The architecture is intentionally boring. Each layer has one job.

Storage

Cloudflare R2

Object storage that's S3-compatible and bills $0.015/GB stored. Egress to the internet via Cloudflare's edge is free.

Delivery

cdn.katalyst-crm.com

Custom domain on the R2 bucket. Every read goes through Cloudflare's edge cache. The API is never in the byte path.

Catalog

Go API + Postgres

Small Go binary on Railway. Owns auth, tenant policy, presigned-URL minting, and the metadata rows. Egress here stays flat regardless of image traffic.

Uploads

Direct-to-R2 presigned

Client → R2 directly. The API hands out a one-time signed URL and verifies completion. A 5 GB upload costs the same in server bandwidth as a 5 KB one.

Common questions

What if a URL returns 404?

Most likely you're missing the /t1/cloudinary/ path prefix, or the page hasn't had its old Cloudinary URLs swapped yet. Paste the URL into Slack and someone can confirm the asset is in the bucket.

Can I resize an image on the fly?

Not yet. Phase 3 of the build wires up Cloudflare Image Transformations so URLs like cdn-cgi/image/width=800,format=auto/<key> serve the right variant at the edge.

What does this cost monthly?

Around $5/month total — fixed compute for the API + Postgres + a few cents of R2 storage. The bill does not scale with image traffic; that's the whole point of the architecture.