BACKBLAZEFIELD GUIDE · BY NIX UNOFFICIAL
EXECUTE / FILE 17

17. POC and demo scripts

A POC is a decision instrument. Write the success criteria before you write the first command.

POC charter template

FieldExample
WorkloadVeeam SOBR capacity tier, 40 TB subset
Success criteria1) Backup job completes nightly within window. 2) Object Lock prevents deletion by admin key. 3) Restore of 2 TB VM set completes in under X hours. 4) Projected 3-year TCO under $Y.
Duration14 to 30 days
OwnersCustomer: backup admin. Backblaze: SE.
DataNon-production or copy
ExitSigned decision meeting on day N

Backblaze advertises a free POC for 50 TB+ (cloud migration and CDN pages: “Want to run a free proof of concept with more than 50TB?”).

Demo 0: setup (2 minutes)

# b2 CLI (python)
pip install --upgrade b2
b2 account authorize            # prompts for keyID and applicationKey
b2 bucket create --help         # check flags for your CLI version

CLI syntax changed in b2 CLI v4 (subcommands like b2 bucket create, b2 file upload). Older docs show b2 create-bucket. Run b2 --help before the demo. [verify flags against installed version]

Create a bucket-scoped key in the web console for the demo. Never demo with the master key.

Demo 1: S3 drop-in with aws CLI (5 minutes)

export AWS_ACCESS_KEY_ID=<b2 keyID>
export AWS_SECRET_ACCESS_KEY=<b2 applicationKey>
export EP=https://s3.us-west-004.backblazeb2.com   # copy exact endpoint from bucket page

aws s3 mb s3://nix-demo-bucket --endpoint-url $EP
aws s3 cp ./sample.mp4 s3://nix-demo-bucket/media/sample.mp4 --endpoint-url $EP
aws s3 ls s3://nix-demo-bucket --recursive --endpoint-url $EP
aws s3 presign s3://nix-demo-bucket/media/sample.mp4 --expires-in 3600 --endpoint-url $EP

Say: “Same CLI. I changed two things: the endpoint and the keys.”

Demo 2: boto3 (5 minutes)

import boto3
s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.us-west-004.backblazeb2.com",
    aws_access_key_id="<keyID>",
    aws_secret_access_key="<applicationKey>",
)
s3.upload_file("sample.mp4", "nix-demo-bucket", "media/sample.mp4")
for o in s3.list_objects_v2(Bucket="nix-demo-bucket", Prefix="media/").get("Contents", []):
    print(o["Key"], o["Size"])
url = s3.generate_presigned_url(
    "get_object", Params={"Bucket": "nix-demo-bucket", "Key": "media/sample.mp4"}, ExpiresIn=900
)
print(url)
# presigned PUT for direct browser/device upload
put_url = s3.generate_presigned_url(
    "put_object", Params={"Bucket": "nix-demo-bucket", "Key": "uploads/user1.jpg"}, ExpiresIn=900
)

Demo 3: Object Lock, the money demo (7 minutes)

import boto3, datetime
s3 = boto3.client("s3", endpoint_url=EP, aws_access_key_id=KID, aws_secret_access_key=KEY)

s3.create_bucket(Bucket="nix-immutable-demo", ObjectLockEnabledForBucket=True)
until = datetime.datetime.utcnow() + datetime.timedelta(days=1)
r = s3.put_object(
    Bucket="nix-immutable-demo", Key="backups/restorepoint.vbk", Body=b"pretend backup",
    ObjectLockMode="GOVERNANCE",            # use COMPLIANCE only if you accept paying until expiry
    ObjectLockRetainUntilDate=until,
)
vid = r["VersionId"]
try:
    s3.delete_object(Bucket="nix-immutable-demo", Key="backups/restorepoint.vbk", VersionId=vid)
except Exception as e:
    print("Delete blocked:", e)            # AccessDenied: object is locked
print(s3.get_object_retention(Bucket="nix-immutable-demo", Key="backups/restorepoint.vbk", VersionId=vid))

Say: “That was my key. Imagine it is the attacker’s. The restore point is still there.”

Demo hygiene: use GOVERNANCE and 1 day in demos. Compliance mode on a demo bucket means paying for it until expiry. Object Lock cannot be turned off on the bucket afterwards.

Demo 4: rclone migration (8 minutes)

rclone config create b2s3 s3 provider=Other \
  access_key_id=<keyID> secret_access_key=<applicationKey> \
  endpoint=s3.us-west-004.backblazeb2.com

# or native backend
rclone config create b2native b2 account=<keyID> key=<applicationKey>

# copy from AWS (configured as remote 'aws') to B2 with parallelism and checksum compare
rclone copy aws:source-bucket b2s3:nix-demo-bucket \
  --transfers 64 --checkers 32 --s3-chunk-size 64M --checksum --progress

rclone check aws:source-bucket b2s3:nix-demo-bucket --one-way

Tune --transfers and chunk size to bandwidth. Show rclone check output as integrity proof.

Demo 5: lifecycle and versions (3 minutes)

Web console: Bucket Settings → Lifecycle Settings. Show “Keep only the last version” vs custom rule with prefix. Explain hide vs delete. Or native:

b2 bucket update nix-demo-bucket allPrivate \
  --lifecycle-rules '[{"fileNamePrefix":"tmp/","daysFromUploadingToHiding":7,"daysFromHidingToDeleting":1}]'

[verify flag name for your CLI version]

Demo 6: Event Notifications (5 minutes, needs access enabled by Support)

  1. Spin up a webhook receiver (e.g., a Cloudflare Worker or python -m http.server behind a tunnel).
  2. Console: Bucket → Event Notifications → add rule: event b2:ObjectCreated:* [verify event type names], prefix media/, endpoint URL, signing secret.
  3. Upload a file; show the POST payload; verify the HMAC.

Demo 7: MCP server with a scoped key (5 minutes)

  1. Create a read-only key on one bucket.
  2. Configure an MCP client (Claude Desktop, Cursor, etc.) with the B2 MCP Server per the docs repo.
  3. Ask: “List the 10 largest files in nix-demo-bucket.” Then ask it to delete one. Show the tool is not available.
  4. Swap to a write key scoped to outputs/ prefix; show the tool list grow.

Demo 8: throughput test (AI POCs)

# parallel download test from a GPU node
rclone copy b2s3:dataset/shards/ /local/nvme/ --transfers 128 --multi-thread-streams 16 --progress
# or s5cmd for high-parallel S3
s5cmd --endpoint-url $EP --numworkers 256 cp 's3://dataset/shards/*' /local/nvme/

Record GB/s, node count, object size, region pair. Compare to target from discovery. If short, discuss Overdrive.

POC scorecard

CriterionTargetResultPass
Ingest rateX TB/day
Restore / read rateY GB/s
Immutability enforcedDelete fails
Integration works unmodifiedYes
Projected 3-yr TCO≤ $Z
Security reviewPassed

Failure modes to pre-empt

  • Wrong endpoint region → ‘InvalidAccessKeyId’ or auth errors.
  • Using master key with S3 API → works but bad practice; also some restrictions.
  • SigV2 client → fails.
  • Object Lock not enabled before Veeam connects → immutability option unavailable.
  • Tiny objects with huge parallelism → measure ops, not GB/s.