Object Storage Integration on Zerops
Zerops Object Storage is S3-compatible (MinIO). Always set AWS_USE_PATH_STYLE_ENDPOINT: true. Use env var references ${storage_*} for credentials. Container filesystem is lost on deploy — use Object Storage for any files that must persist across deployments.
Environment Variables
When you create an Object Storage service, Zerops auto-generates these env vars (prefix with hostname for cross-service access, e.g. ${storage_apiUrl}):
| Variable | Description |
|---|---|
apiUrl | S3 endpoint URL — full https://... URL ready for any S3 SDK's endpoint option |
apiHost | S3 endpoint host only (no scheme); use only if the client library needs host separately |
accessKeyId | S3 access key |
secretAccessKey | S3 secret key |
bucketName | Auto-generated bucket name (hostname + random prefix, immutable) |
quotaGBytes | Bucket quota in GB |
projectId | Project ID (Zerops-generated) |
serviceId | Service ID (Zerops-generated) |
hostname | Service hostname |
Use ${storage_apiUrl} as the S3 endpoint — it carries the complete https:// scheme and is what every S3 SDK's endpoint option expects. The apiHost variant is host-only; if a client library requires host separately, combine https://${storage_apiHost} manually — never http://. The object-storage gateway rejects plaintext HTTP with a 301 redirect to the HTTPS equivalent, and most S3 SDKs don't follow the redirect automatically. The symptom of a misconfigured endpoint is UnknownError or connection-refused on the first bucket call.
Reference them in zerops.yml run.envVariables:
Path Style Endpoint (Required)
Zerops uses MinIO which requires path-style URLs (not virtual-hosted):
Every S3 client must be configured for path-style access.
Framework Integration
PHP (Laravel — Flysystem)
Package: league/flysystem-aws-s3-v3
Node.js (AWS SDK v3)
Package: @aws-sdk/client-s3
Python (boto3)
Package: boto3
Java (AWS SDK)
S3Client s3 = S3Client.builder()
.endpointOverride(URI.create(System.getenv("S3_ENDPOINT")))
.serviceConfiguration(S3Configuration.builder()
.pathStyleAccessEnabled(true) // REQUIRED
.build())
.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create(
System.getenv("S3_ACCESS_KEY"),
System.getenv("S3_SECRET_KEY"))))
.region(Region.US_EAST_1)
.build();
import.yaml Definition
Predefined policies (objectStoragePolicy):
private— no anonymous access (documents, backups)public-read— anonymous list + get (media, avatars, static assets)public-objects-read— anonymous get only, no listing (direct links only)public-write— anonymous put onlypublic-read-write— full anonymous access
Custom policy: use objectStorageRawPolicy with IAM Policy JSON instead (template var {{ .BucketName }} available).
Each service = one bucket (auto-named, immutable). Need multiple buckets? Create multiple services.
When to Use Object Storage
| Scenario | Use Object Storage? |
|---|---|
| User uploads (avatars, documents) | Yes — lost on deploy |
| Media files (images, videos) | Yes — serve via public URL |
| Build artifacts | No — deploy via zerops.yaml |
| Temporary files | No — container disk is fine |
| Logs | No — use Zerops logging |
| Database dumps | Yes — for backup storage |
Gotchas
forcePathStyle: true/AWS_USE_PATH_STYLE_ENDPOINT: trueis REQUIRED: Zerops uses MinIO which doesn't support virtual-hosted style- Container filesystem is replaced on deploy: Files on disk survive restarts but are lost when a new container is created (deploy, scale-up). Always use Object Storage for persistent data
- Region is required but ignored: Set
us-east-1— MinIO ignores it but SDKs require it - Public URL format:
{apiUrl}/{bucketName}/path/to/file - Independent infrastructure: Object Storage runs on separate infra from other services — accessible from Zerops and remotely over internet
- One bucket per service: Bucket name auto-generated (hostname + random prefix), cannot be changed. Need multiple buckets? Add more object-storage services
- No Zerops backup: Object Storage is not covered by the Zerops backup system
- No autoscaling: Quota (1-100 GB) must be set manually, changeable in GUI after creation