Zaroz
Object storage

Object storage quick start

Zaroz object storage speaks the S3 API, so the tools you already use (the AWS CLI, boto3, the AWS SDK for JavaScript, rclone, most backup programs) work with a different endpoint and your own keys. Each object storage subscription has one bucket.

1. Create the bucket

  1. Open Storage → Object storage in the console and buy a plan (or open the subscription you already have).
  2. Create the bucket: give it a name you will recognise, and optionally a storage cap (1 GiB to 100 TiB, 100 GiB by default).
  3. The bucket page shows the four values every S3 client asks for:
ValueWhat it isExample
EndpointThe S3 URL to point your client atthe URL on your bucket page
Bucket nameThe real name to use in requests, zb- plus 32 characters. It is not the display name you chose.zb-3f2a9c...
Regionus-east-1. Clients insist on a region; this is the one to give them. It does not say where the data lives.us-east-1
AddressingPath-style: ENDPOINT/BUCKET/KEY. Virtual-hosted style (BUCKET.ENDPOINT) is not served.forcePathStyle / addressing_style: path

2. Make an access key

Open the bucket's Access keys tab and create a key. Choose its scope:

  • Read and write can list, download, upload, copy and delete objects.
  • Read only can list and download. Use it for anything that only reads, such as a website, a deploy script or a colleague who only needs to look.

A key only ever works on its own bucket. You can hold up to 20 active keys per bucket; give each one a name for the thing that uses it, so you can revoke exactly that one later.

The secret is shown once

Copy the secret access key the moment the key is created. Zaroz keeps only a fingerprint of it and can never show it again. If you lose it, revoke the key and create another.

Revoking a key stops it immediately. Nothing else changes.

3. Connect

Put the values in the environment (the AWS CLI, boto3 and the JavaScript SDK all read these two variables):

TerminalCode
export AWS_ACCESS_KEY_ID="<your access key id>" export AWS_SECRET_ACCESS_KEY="<your secret access key>" export AWS_DEFAULT_REGION="us-east-1" export ENDPOINT="<the endpoint on your bucket page>" export BUCKET="<the bucket name on your bucket page>"

AWS CLI

TerminalCode
aws s3 cp ./photo.jpg "s3://$BUCKET/photos/photo.jpg" --endpoint-url "$ENDPOINT" aws s3 ls "s3://$BUCKET/photos/" --endpoint-url "$ENDPOINT" aws s3 sync ./site "s3://$BUCKET/site" --endpoint-url "$ENDPOINT" aws s3 cp "s3://$BUCKET/photos/photo.jpg" ./copy.jpg --endpoint-url "$ENDPOINT"

Large files are uploaded in parts automatically. You can also set the endpoint once in ~/.aws/config with endpoint_url = ... and s3 = addressing_style = path.

Python (boto3)

Code
import os import boto3 from botocore.config import Config s3 = boto3.client( "s3", endpoint_url=os.environ["ENDPOINT"], region_name="us-east-1", config=Config(s3={"addressing_style": "path"}), ) bucket = os.environ["BUCKET"] s3.put_object(Bucket=bucket, Key="hello.txt", Body=b"hello") print(s3.get_object(Bucket=bucket, Key="hello.txt")["Body"].read()) for item in s3.list_objects_v2(Bucket=bucket).get("Contents", []): print(item["Key"], item["Size"]) s3.upload_file("backup.tar.gz", bucket, "backups/backup.tar.gz")

JavaScript (AWS SDK v3)

JavascriptCode
import { S3Client, PutObjectCommand, GetObjectCommand, ListObjectsV2Command } from "@aws-sdk/client-s3"; const s3 = new S3Client({ endpoint: process.env.ENDPOINT, region: "us-east-1", forcePathStyle: true, // required: virtual-hosted style is not served requestChecksumCalculation: "WHEN_REQUIRED", // needed for presigned uploads, see below // credentials come from AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY }); const Bucket = process.env.BUCKET; await s3.send(new PutObjectCommand({ Bucket, Key: "hello.txt", Body: "hello" })); const object = await s3.send(new GetObjectCommand({ Bucket, Key: "hello.txt" })); console.log(await object.Body.transformToString()); const listing = await s3.send(new ListObjectsV2Command({ Bucket })); console.log(listing.Contents?.map((o) => o.Key));

Any other S3 tool takes the same four values. In rclone, choose provider "Other", set the endpoint, and set force_path_style = true.

Browse and upload in the console

The bucket's Objects tab is a file browser: folders, drag-and-drop upload (large files go up in parts, with progress and a cancel button, up to 625 GiB per object), download, delete and, for a public bucket, a button that copies an object's public URL.

The console never carries your files. It asks Zaroz for a short-lived link (15 minutes) and your browser talks to the storage directly, so the same billing rules apply as for any S3 client:

  • Downloads count as data transfer out and are billed per GiB. So do previews: the console loads nothing on its own (no thumbnails), shows a preview only when you click it, and asks first for files over 1 MiB.
  • Uploads are free.
  • Listing folders is not billed.

While a bucket is over its cap you can still browse, download and delete, but not upload. While it is suspended you can see the names and sizes but not download, upload or delete.

Share files publicly

In the bucket's Settings, turn on Public read. Anyone can then download an object without a key at:

Code
ENDPOINT/BUCKET/path/to/object.jpg
  • Public read covers downloading objects only. Nobody can list the bucket, upload or delete without a key, and your other buckets are unaffected.
  • Turning it off takes effect within a few minutes. Everything downloaded in the meantime is billed as normal egress.
  • If you only need to share a file for a while, prefer a presigned link and keep the bucket private.

A presigned URL lets someone download (or upload) one object for a limited time without having a key. Your code makes it with its own key; the URL then stands alone.

TerminalCode
aws s3 presign "s3://$BUCKET/report.pdf" --expires-in 3600 --endpoint-url "$ENDPOINT"
Code
url = s3.generate_presigned_url( "put_object", Params={"Bucket": bucket, "Key": "uploads/a.png"}, ExpiresIn=900 )
JavascriptCode
import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; const url = await getSignedUrl(s3, new GetObjectCommand({ Bucket, Key: "report.pdf" }), { expiresIn: 3600 });

The link carries the permissions of the key that made it, and stops working if that key is revoked or the bucket is suspended.

JavaScript presigned uploads

Recent versions of the AWS SDK for JavaScript v3 add a checksum of the (empty) body to a presigned upload URL, and the upload then fails with BadDigest. Create the client with requestChecksumCalculation: "WHEN_REQUIRED", as in the example above, and presigned uploads work. Downloads and boto3 are not affected.

Calling your bucket from a web page

Browsers only call the bucket directly from the Zaroz console: the bucket's CORS rules allow the console's origin and nothing else, and your keys cannot change them. A page on your own site cannot upload or download straight from the bucket. Generate presigned URLs on your server (see above) and hand those to the page, or use public read for files that anyone may download.

Limits

Buckets per subscription1
Active keys per bucket20
Storage cap1 GiB to 100 TiB (default 100 GiB), changeable any time
AddressingPath-style only
Region nameus-east-1

The storage cap protects your bill. When the stored data reaches the cap, uploads stop: every key can still list and download, and read-write keys can still delete objects, so you can free space yourself. Delete enough, or raise the cap in Settings, and uploads resume within about ten minutes. Usage is measured hourly, so the cap can be overshot slightly and the change takes up to an hour to show.

What happens to your data

  • Unpaid or suspended subscription: your keys stop working and public links go dark, but the data is kept. Pay the invoice and access returns within about ten minutes.
  • Cancelled or ended subscription: the bucket is scheduled for deletion and its data is permanently removed after 7 days. Download what you need before then.
  • Delete the bucket yourself: the same 7-day period applies before the data is purged.

What it costs

The bill has three parts, shown on your plan's page:

  1. A monthly minimum (the plan price), charged up front.
  2. Storage, per GiB-month, measured hourly and averaged over the month.
  3. Downloads (egress), per GiB sent out of the bucket.

Uploads (ingress) are free. The minimum counts toward storage and egress first: you pay extra only for usage worth more than the minimum, so a small bucket costs exactly the plan price. The bucket's Usage tab shows storage and egress so far this month.

Troubleshooting

You seeUsually
AccessDenied on an uploadThe key is read-only, the bucket is over its cap (deleting still works), or the subscription is suspended
AccessDenied listing a public bucket without a keyExpected: public read serves objects, not listings
SignatureDoesNotMatch or a DNS errorThe client is using virtual-hosted addressing: turn on path-style
BadDigest on a presigned upload from JavaScriptSet requestChecksumCalculation: "WHEN_REQUIRED"
NoSuchBucketYou used the display name instead of the zb-... bucket name
Last modified on