A high-performance, self-hosted distributed S3-compatible object storage system written in Zig Lang.
Author: Carsen Klock (@metaspartan)
|
Seamlessly integrates with the AWS CLI, SDKs, and standard S3 clients. A drop-in replacement for Cloudflare R2, Garage, MinIO, or AWS S3. |
Built on a consistent hashing ring with a gossip protocol. Storage capacity and throughput scale linearly as you add nodes. |
|
Built-in |
Encryption at Rest: AES-256-GCM encryption. |
|
Versioning: Protect against accidental deletes with object versioning. |
Zero Dependencies: Single static binary (Linux/macOS). |
- Getting Started
- Deployment Guide - Cloudflare Tunnel, Nginx, Systemd
- Backup & Restore
- RAM: Minimum 128MB, Recommended 512MB+
- CPU: 1 core minimum
- Disk: Dependent on data size (Standard SSD/HDD)
- OS: Linux or macOS
docker compose up -dZ4 now uses a robust key management system. You must generate API keys using the CLI to access the S3 API.
Generate an API key:
# Create a key named 'admin'
docker exec z4-node1 /app/z4 key create adminCreate a bucket and grant access:
# Create a bucket
docker exec z4-node1 /app/z4 bucket create mybucket
# Grant 'admin' key full access to 'mybucket'
docker exec z4-node1 /app/z4 bucket allow mybucket --key admin --read --write --ownerservices:
z4:
build: .
ports:
- "9670:9670" # S3 API
- "9671:9671" # Gossip protocol
volumes:
- ./data:/app/data
environment:
- Z4_ENCRYPTION_KEY=${Z4_ENCRYPTION_KEY:-}
command: ["/app/z4", "server", "--vnodes", "150"]
restart: alwaysZ4 includes a built-in CLI for administration.
| Command | Description |
|---|---|
z4 key create <name> |
Generate a new API key (Access Key ID + Secret) |
z4 key list |
List all API keys |
z4 key info <name> |
Show key details and permissions |
z4 key delete <name> |
Delete an API key |
| Command | Description |
|---|---|
z4 bucket create <name> |
Create a new bucket |
z4 bucket list |
List all buckets |
z4 bucket allow <bucket> --key <name> ... |
Grant permissions (flags below) |
z4 bucket deny <bucket> --key <name> |
Revoke access to a bucket |
Permission Flags:
--read: Allow GetObject, ListObjects, etc.--write: Allow PutObject, DeleteObject, etc.--owner: Full control (ACLs, Policy, etc.)
| Option | Default | Description |
|---|---|---|
--port |
9670 | HTTP API port |
--gossip-port |
9671 | Cluster gossip port (UDP) |
--data |
data | Storage directory |
--id |
node1 | Unique node identifier |
--join |
- | Seed node address (host:port) |
--threads |
auto | Worker thread count |
--vnodes |
150 | Virtual nodes per physical node |
--debug |
false | Enable debug logging |
| Variable | Description |
|---|---|
Z4_ENCRYPTION_KEY |
32-byte AES-256-GCM encryption key |
After creating a key via CLI:
aws configure set aws_access_key_id <YOUR_ACCESS_KEY_ID>
aws configure set aws_secret_access_key <YOUR_SECRET_KEY>
aws --endpoint-url http://localhost:9670 s3 cp file.txt s3://mybucket/
aws --endpoint-url http://localhost:9670 s3 ls s3://mybucket/data/
βββ _z4meta/ # Secure metadata (not S3-accessible)
β βββ keys/ # API keys and permissions
β βββ buckets/ # ACLs, policies, encryption config
β βββ objects/ # Object tags
βββ mybucket/
βββ a3/7f/ # Wyhash-sharded directories
βββ file.txt
- Consistent hashing with configurable virtual nodes (default: 150)
- Replication factor 3 for fault tolerance
- HTTP 307 redirects route requests to responsible nodes
- UDP gossip for node discovery and health checks
zig build # Debug
zig build -Doptimize=ReleaseFast # Release
./scripts/build-all.sh v1.0.0 # Cross-compile all platforms| Feature | Endpoint | Status | Notes |
|---|---|---|---|
| Buckets | |||
| CreateBucket | PUT /{bucket} |
β | |
| DeleteBucket | DELETE /{bucket} |
β | |
| ListBuckets | GET / |
β | |
| GetBucketLocation | GET /{bucket}?location |
β | Default: us-east-1 |
| Objects | |||
| PutObject | PUT /{bucket}/{key} |
β | Streaming & Large files supported |
| GetObject | GET /{bucket}/{key} |
β | Range requests supported |
| DeleteObject | DELETE /{bucket}/{key} |
β | |
| HeadObject | HEAD /{bucket}/{key} |
β | |
| CopyObject | PUT /{bucket}/{key} |
β | Header: x-amz-copy-source |
| Multipart Upload | |||
| CreateMultipartUpload | POST /{bucket}/{key}?uploads |
β | |
| UploadPart | PUT /{bucket}/{key}?partNumber=... |
β | |
| CompleteMultipartUpload | POST /{bucket}/{key}?uploadId=... |
β | |
| AbortMultipartUpload | DELETE /{bucket}/{key}?uploadId=... |
β | |
| Advanced | |||
| Bucket Policies | PUT/GET/DELETE /{bucket}?policy |
β | Allow/Deny support |
| Bucket ACLs | PUT/GET /{bucket}?acl |
β | |
| Object ACLs | PUT/GET /{bucket}/{key}?acl |
β | |
| Versioning | PUT/GET /{bucket}?versioning |
β | |
| Encryption | PUT/GET/DELETE /{bucket}?encryption |
β | AES-256-GCM (Server-Side) |
| Lifecycle | PUT/GET/DELETE /{bucket}?lifecycle |
β | Expiration rules |
| Tagging | PUT/GET/DELETE /{bucket}/{key}?tagging |
β | Bucket & Object tagging |
Contributions are welcome! Please open an issue or submit a pull request.
MIT License. Copyright (c) 2025-2026 Carsen Klock