Skip to content

S3

Zhang can read and write the ledger files directly in a bucket of Amazon S3 or of an S3-compatible storage (Cloudflare R2, MinIO, Aliyun OSS, Tencent COS, Backblaze B2 and others). The server itself then keeps no data, which suits containers and hosting platforms.

Select the data source with --source s3 or ZHANG_DATA_SOURCE=s3, and configure it with environment variables:

Environment variable Required Example Description
ZHANG_S3_BUCKET yes my-ledger The bucket that holds the ledger.
ZHANG_S3_ROOT no /accounting The folder (key prefix) of the ledger in the bucket. Default /.
ZHANG_S3_ENDPOINT no https://<account_id>.r2.cloudflarestorage.com The endpoint of the storage service, needed for everything but Amazon S3. Falls back to AWS_ENDPOINT_URL, AWS_ENDPOINT or AWS_S3_ENDPOINT, then to https://s3.amazonaws.com.
ZHANG_S3_REGION see description us-east-1 The region. Falls back to AWS_REGION, then AWS_DEFAULT_REGION. One of them must be set. Use auto for Cloudflare R2 and us-east-1 for MinIO.
ZHANG_S3_ACCESS_KEY_ID no AKIA… The access key. Without it, the standard AWS credential chain is used: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, the ~/.aws files, then the instance metadata.
ZHANG_S3_SECRET_ACCESS_KEY no The secret of the access key.
ZHANG_S3_SESSION_TOKEN no The session token of temporary credentials.
ZHANG_S3_VIRTUAL_HOST_STYLE no true true or 1 to address the bucket as https://<bucket>.<endpoint> instead of https://<endpoint>/<bucket>. Some providers, such as Aliyun OSS, accept only this style.

The <PATH> argument of zhang serve is ignored: the ledger is the folder ZHANG_S3_ROOT of the bucket. The main file is still selected with --endpoint (default main.zhang), relative to that folder.

  1. Create a bucket and upload your ledger files into it, for example main.zhang under the prefix accounting/.
  2. Create credentials that may read, write and list objects in the bucket (GetObject, PutObject and ListBucket on AWS).
  3. Start Zhang with the variables set:
Terminal window
ZHANG_DATA_SOURCE=s3 \
ZHANG_S3_BUCKET=my-ledger \
ZHANG_S3_ROOT=/accounting \
ZHANG_S3_REGION=us-east-1 \
ZHANG_S3_ACCESS_KEY_ID=your_access_key \
ZHANG_S3_SECRET_ACCESS_KEY=your_secret \
zhang serve . --endpoint main.zhang

With Docker, for a ledger at the root of a Cloudflare R2 bucket:

Terminal window
docker run --name zhang -d -p 8000:8000 \
-e ZHANG_DATA_SOURCE=s3 \
-e ZHANG_S3_BUCKET=my-ledger \
-e ZHANG_S3_ENDPOINT=https://<account_id>.r2.cloudflarestorage.com \
-e ZHANG_S3_REGION=auto \
-e ZHANG_S3_ACCESS_KEY_ID=your_access_key \
-e ZHANG_S3_SECRET_ACCESS_KEY=your_secret \
kilerd/zhang:latest
  • For a public demo, use credentials that can read and list objects but cannot write or delete them. See the Render demo guide for setup and the limitations of the editing controls.
  • Zhang does not watch the bucket. When the files change outside Zhang, use the reload button of the web UI, or restart Zhang. What you record in the web UI is written to the bucket and reloaded right away.
  • The web UI writes new entries, uploaded documents and passkeys to the bucket, in the same places as on the local file system.
  • Plugin modules and the documents the web UI has opened are cached in the .cache folder of the working directory, on the machine that runs Zhang, see The .cache folder.
  • Zhang stops at startup with cannot build s3 operator and region is missing: set ZHANG_S3_REGION (or AWS_REGION). For a service that ignores regions, us-east-1 or auto usually works.
  • Zhang stops at startup with ZHANG_S3_BUCKET must be set: the bucket is required.
  • Access denied: give the credentials read, write and list permissions on the bucket and the prefix.
  • The web UI shows an empty ledger: Zhang did not find the main file and started with an empty ledger. The main file is read from <ZHANG_S3_ROOT>/<endpoint> in the bucket: check ZHANG_S3_ROOT and --endpoint.