Skip to content

Backblaze + Cloudflare ​

Backblaze has a partnership with Cloudflare to provide free data transfer.

The Cloudflare Worker in 5stack-panel (cloudflare-workers/backblaze-proxy/) signs S3 v4 requests in front of your B2 bucket and serves them through Cloudflare's edge, giving you free B2 → Cloudflare egress and edge caching so popular clips/demos don't re-hit B2 on every view. It serves demos, clips, news images, event media and map assets.

1. Point the panel at your bucket ​

The deploy script reads the bucket from the panel's own S3 configuration, so set it up there first:

  • overlays/config/s3-config.env: S3_BUCKET and S3_ENDPOINT (whatever your bucket lists under "Endpoint", e.g. s3.us-east-005.backblazeb2.com)
  • overlays/local-secrets/s3-secrets.env: S3_ACCESS_KEY and S3_SECRET

If your secrets live in Vault, the script reads the keys from your cluster instead. Either way it checks them with Backblaze before deploying anything, and asks you for them if Backblaze rejects them.

2. Deploy ​

From the directory you installed the panel in (5stack-panel), run:

bash
./backblaze-proxy.sh

Run it where kubectl reaches the panel: on the panel's server, as root on a k3s install (/etc/rancher/k3s/k3s.yaml is readable only by root), or anywhere KUBECONFIG points at the panel. It asks the panel's database whether clip links are signed.

It needs Node.js 22 or newer (for npx wrangler, Cloudflare's deploy tool) and walks you through the rest:

  1. The hostname. The worker gets a hostname of its own on a domain you have on Cloudflare, cf.<your domain> by default. It can't share one of the panel's hostnames: the worker takes over /demo*, /clips*, /news*, /maps* and /events* on it, and on your demos domain that would break the panel's own demo uploads.
  2. Signing in to Cloudflare. Pick a browser on this machine, a code you enter on another device (for a server without a browser), or an API token made from the Edit Cloudflare Workers template. A token is only used for that run.
  3. The DNS record. If the hostname has no record yet, it tells you what to add: an AAAA record pointing at 100:: with the proxy on (orange cloud). The address is only a placeholder, because the worker answers every request itself. It links to your domain's DNS page and checks again once you have added it.
  4. Signed clip links. It asks the panel's database whether its API signs clip and lineup file links with the bucket keys the worker gets, and asks Cloudflare whether the worker requires signed links now. It turns them on once the panel signs them, warning that every panel using the worker must already sign them. Once they are on, it keeps them on when it can't reach the panel, and turns them off only if you answer yes to a question that defaults to no. With nobody there to answer, it deploys nothing. See Signed clip links.
  5. Deploying. It shows the hostname and bucket, then deploys the worker, stores the bucket keys as worker secrets and adds its routes. Routes the worker already has on other hostnames are kept, so links that still use an older hostname keep working.
  6. Checking it. It reads a file through the worker to make sure it can reach your bucket.
  7. Pointing the panel at it. It saves the hostname as CLOUDFLARE_WORKER_DOMAIN in overlays/config/api-config.env, asking first if the panel was using a different one, and applies it straight away, or offers to run ./update.sh when it can't. Every demo, clip and media download link is built from it.
  8. Smart Tiered Cache. It checks whether it is on for your domain. Signed in with an API token, it can turn it on for you; signed in through the browser or a device code, it links you to the setting, because that sign-in can't change cache settings.

Run it again at any time to update the worker, and after every panel update, rollback or change to S3_SECRET (see Signed clip links).

Check that it works ​

Go to Settings → Application → Demos:

  • Cloudflare delivery shows the worker as Online when it answers and Backblaze accepts its keys. It shows Offline when the worker isn't answering or Backblaze rejects its keys, which breaks every download that isn't cached yet; run the script again with the keys the panel uses. A worker deployed before these checks shows Needs attention until you run the script again.
  • Storage check writes a test file to your bucket, reads it back in your browser, and checks the worker, showing each step's result.

Once the panel signs them, the worker refuses a clip, clip thumbnail or utility lineup file without a signed, unexpired link, and only people who may see a clip get one. Links expire: 1–2 years for a public clip or lineup, so embeds keep working, and 6–12 hours for anything else. Share a clip's page (/clips/<id>), not its file link: the page always hands out a fresh link.

  • Re-run ./backblaze-proxy.sh after every panel update, every rollback, and every change to S3_SECRET. Each run decides again whether the worker requires signed links; updating or rolling back the panel doesn't touch the worker.
  • One worker, several panels. All panels on the same Cloudflare account and bucket share the 5stack worker. Update every one of them before running the script from any of them: once the worker requires signed links, a panel that doesn't sign them loses its clips.
  • Turning it off (answering yes when a panel doesn't sign) affects every panel on the worker: their private clips can be downloaded by anyone with the link until the script turns it back on.
  • Revocation isn't instant. A clip or lineup made private keeps the links already handed out working until they expire, up to two years for one that was public.

Changing the bucket keys ​

The worker keeps its own copy of S3_ACCESS_KEY and S3_SECRET: it reads B2 with them and checks signed clip links with a key derived from S3_SECRET. After changing them in overlays/local-secrets/s3-secrets.env or Vault:

  1. Run ./update.sh so the API restarts with them.
  2. Run ./backblaze-proxy.sh, giving it the same keys.

Until the second step, the worker refuses the links the API signs with the new S3_SECRET. If the script sees that the keys don't match the API's, it says so and doesn't turn signed links on.

Caching ​

Edge caching is enabled in the worker by default, cf.cacheEverything plus a Cache-Control: public, max-age=2592000, immutable response header. Clip/demo objects are UUID-keyed so they're safe to cache for the full 30-day window Cloudflare allows on the Free tier. The first request to a clip warms the edge cache; subsequent viewers (including <video> Range seeks) are served from Cloudflare without touching B2.

Cloudflare's edge cache is per-datacenter. Without Tiered Cache, a clip viewed first from London is still a cold miss in Tokyo and re-fetches from B2. Tiered Cache lets edges pull from each other before going to origin, so each clip is fetched from B2 once globally instead of once per region.

In the Cloudflare Dashboard, select your zone, then go to Caching → Tiered Cache and enable Smart Tiered Cache Topology. It's free on all plans and is the single biggest reduction in B2 cold-miss traffic you can make.

Free-tier limits to watch ​

  • Workers Free: 100,000 requests/day across the whole account. Every clip view + every video Range seek consumes a request. Monitor under Workers & Pages → your worker → Metrics. The $5/mo Workers Paid plan includes 10 million requests a month, then charges per million.
  • Per-file cache cap on Free: 512 MB. Files larger than this bypass the edge cache (egress is still free via the Bandwidth Alliance, but they re-fetch from B2 each time). Most clips and demos are well under this.