Zeabur Object Storage Deployment & Integration
Always usenpx zeabur@latestto invoke Zeabur CLI. Never usezeaburdirectly or any other installation method. Ifnpxis not available, install Node.js first.
Deploy Object Storage
Before deploying, you MUST load thezeabur-templateskill first to understand what Zeabur templates are, how they work, and how to deploy them. This skill only covers object storage-specific integration — all template knowledge lives inzeabur-template.
Search for a storage template:
npx zeabur@latest template search minio -i=false --jsonPick the template with the highest deployment count.
- Default to MinIO if the user doesn't specify — most widely supported, built-in web console, auto-creates a default bucket.
- Recommend RustFS if the user wants lightweight/minimal or mentions RustFS specifically.
After Deployment: How to Connect
For object storage, you need: S3 API endpoint (how to connect), access key + secret key (how to authenticate), and a bucket name.
How to connect — service network
npx zeabur@latest service network --id <storage-service-id> -i=falseThis shows:
- Private Networking — internal
hostname:portfor the S3 API (e.g.,minio.zeabur.internal:9000) - Public Networking — for HTTP ports, it will indicate you need to bind a domain to access externally
MinIO and RustFS ports are HTTP type, so public access is via domain binding, not port forwarding. Bind a domain to the API port via the Dashboard to get an external S3 endpoint (e.g., https://minio-api.zeabur.app).How to authenticate — variable list
npx zeabur@latest variable list --id <storage-service-id> -i=falseThis lists the access key, secret key, and other credentials.
MinIO
Credentials (from variable list)
| Variable | Description |
|---|---|
MINIO_USERNAME | Access Key ID (default: minio) |
MINIO_PASSWORD | Secret Access Key (auto-generated) |
MINIO_DEFAULT_BUCKET | Default bucket name (default: zeabur) |
MINIO_CONSOLE_URL | Web console URL |
Connect from app (same project)
Set these env vars on your app service:
S3_ENDPOINT=http://minio.zeabur.internal:9000
S3_ACCESS_KEY=${MINIO_USERNAME}
S3_SECRET_KEY=${MINIO_PASSWORD}
S3_BUCKET=zeabur
S3_REGION=us-east-1
S3_FORCE_PATH_STYLE=trueThe S3 endpoint is not exposed as a variable — you must hardcode it using the internal hostname from service network.Connect from local machine
Bind a domain to the API port, then use that domain as endpoint:
# MinIO Client (mc)
mc alias set zeabur https://MINIO_API_DOMAIN MINIO_USERNAME MINIO_PASSWORD
mc ls zeabur/
mc cp local-file.txt zeabur/zeabur/
# AWS CLI
aws --endpoint-url https://MINIO_API_DOMAIN s3 lsWeb Console
Open MINIO_CONSOLE_URL in a browser, login with MINIO_USERNAME / MINIO_PASSWORD. MinIO auto-creates a zeabur bucket on first boot.
RustFS
Credentials (from variable list)
| Variable | Description |
|---|---|
RUSTFS_USERNAME | Access Key ID (default: rustfs) |
RUSTFS_PASSWORD | Secret Access Key (auto-generated) |
Connect from app (same project)
Set these env vars on your app service:
S3_ENDPOINT=http://rustfs.zeabur.internal:9000
S3_ACCESS_KEY=${RUSTFS_USERNAME}
S3_SECRET_KEY=${RUSTFS_PASSWORD}
S3_BUCKET=my-bucket
S3_REGION=us-east-1
S3_FORCE_PATH_STYLE=trueThe S3 endpoint is not exposed as a variable — you must hardcode it using the internal hostname fromservice network. Also checkservice listfor the exact service name (may beRustFSnotrustfs).
You must create a bucket first — unlike MinIO, RustFS starts with zero buckets.
Connect from local machine
Bind a domain to the API port, then:
mc alias set zeabur https://RUSTFS_API_DOMAIN RUSTFS_USERNAME RUSTFS_PASSWORD
mc mb zeabur/my-bucket
mc ls zeabur/Web Console
Open the domain bound to port 9001 in a browser, login with RUSTFS_USERNAME / RUSTFS_PASSWORD. Create a bucket before your app can upload files.
SDK Examples
All S3-compatible SDKs need: endpoint, access key, secret key, region, and forcePathStyle: true.
// Node.js (AWS SDK v3)
const { S3Client } = require("@aws-sdk/client-s3");
const s3 = new S3Client({
endpoint: process.env.S3_ENDPOINT,
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY,
secretAccessKey: process.env.S3_SECRET_KEY,
},
region: "us-east-1",
forcePathStyle: true,
});# Python (boto3)
import boto3, os
s3 = boto3.client(
"s3",
endpoint_url=os.environ["S3_ENDPOINT"],
aws_access_key_id=os.environ["S3_ACCESS_KEY"],
aws_secret_access_key=os.environ["S3_SECRET_KEY"],
region_name="us-east-1",
)// Go (aws-sdk-go-v2)
cfg, _ := config.LoadDefaultConfig(ctx,
config.WithRegion("us-east-1"),
config.WithCredentialsProvider(
credentials.NewStaticCredentialsProvider(accessKey, secretKey, ""),
),
)
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
o.BaseEndpoint = aws.String(endpoint)
o.UsePathStyle = true
})Caveats
forcePathStyleis required — Without it, S3 SDKs use virtual-hosted-style URLs (http://bucket.host:9000/key) which won't resolve. This is the #1 cause of "bucket not found" errors.- Create bucket before uploading (RustFS) — MinIO auto-creates a
zeaburbucket; RustFS does not. Create one via the console ormc mb. - S3 endpoint is not a template variable — Hardcode it using the hostname from
service network(internal) or the bound domain (external). - Variable references — Zeabur uses a flat namespace. Set
${MINIO_USERNAME}etc. via the Zeabur Dashboard — the CLI has a known bug with${}expansion. - Console vs API ports — MinIO: API
9000, console9090. RustFS: API9000, console9001. Apps connect to the API port.