Sign inSign up

simota/devcloud-s3

By simota

•Updated 3 days ago

S3-compatible endpoint for local dev and tests, from devcloud (Rust). Listens on MinIO's port 9000.

Image
0

245

simota/devcloud-s3 repository overview

⁠devcloud-s3

A lightweight, S3-compatible endpoint for local development and deterministic tests. It is the S3 service of devcloud⁠, packaged as a standalone Rust binary — no orchestrator, dashboard, or other services.

It listens on MinIO's API port 9000, so it can stand in for MinIO in most local setups. It is not intended for production use or full AWS parity.

⁠Quick start

docker run --rm -p 9000:9000 -v devcloud-s3-data:/data simota/devcloud-s3
export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1
aws --endpoint-url http://localhost:9000 s3 mb s3://my-bucket
aws --endpoint-url http://localhost:9000 s3 cp ./file.txt s3://my-bucket/
aws --endpoint-url http://localhost:9000 s3 ls s3://my-bucket

In the default relaxed auth mode any credentials are accepted. Use path-style addressing in SDKs (for example forcePathStyle: true / s3={'addressing_style': 'path'}).

⁠Docker Compose
services:
  s3:
    image: simota/devcloud-s3:0.3.0
    ports:
      - "9000:9000"
    environment:
      DEVCLOUD_S3_BUCKETS: uploads,backups
    volumes:
      - s3-data:/data
volumes:
  s3-data:

⁠Configuration

VariableDefaultDescription
DEVCLOUD_S3_ADDR0.0.0.0:9000Listen address (host:port).
DEVCLOUD_S3_STORAGE/dataStorage root for buckets and objects.
DEVCLOUD_S3_AUTH_MODErelaxedrelaxed accepts any request; strict verifies AWS SigV4 signatures.
DEVCLOUD_S3_ACCESS_KEY_IDdevAccess key accepted in strict mode.
DEVCLOUD_S3_SECRET_ACCESS_KEY—Secret key used to verify signatures in strict mode.
DEVCLOUD_S3_REGIONus-east-1Region expected in SigV4 signatures in strict mode.
DEVCLOUD_S3_BUCKETS—Comma-separated buckets to create at startup (since 0.3.0). Blank entries are skipped and existing buckets are kept. An invalid bucket name stops startup with exit code 2.

Create buckets at startup:

docker run --rm -p 9000:9000 -e DEVCLOUD_S3_BUCKETS=uploads,backups simota/devcloud-s3

Strict mode example:

docker run --rm -p 9000:9000 \
  -e DEVCLOUD_S3_AUTH_MODE=strict \
  -e DEVCLOUD_S3_ACCESS_KEY_ID=mykey \
  -e DEVCLOUD_S3_SECRET_ACCESS_KEY=mysecret \
  simota/devcloud-s3

The container runs as a non-root user (UID 10001). Data persists in the /data volume; mount a named volume or a host directory writable by that UID. It stops cleanly on SIGTERM (docker stop).

⁠Supported S3 features

FeatureStatus
Buckets: create, head, list, delete, locationYes
Objects: put, get, head, delete, copy, range GET, metadataYes
ListObjects / ListObjectsV2 (prefix, delimiter, pagination, encoding-type=url)Yes
Multipart upload (create, upload part, list, complete, abort)Yes
Content-MD5 validationYes
Conditional requests: If-None-Match on GET/HEAD (304); If-None-Match: * on PutObject, CopyObject, CompleteMultipartUpload (412); x-amz-copy-source-if-none-matchYes (since 0.2.0)
SigV4 header auth and presigned URLsYes — signatures are verified in strict mode
Path-style addressingYes (default)
Virtual-host style ({bucket}.localhost)Partial
Versioning, delete markers, ListObjectVersionsPartial
Bucket policy / ACL metadataPartial — stored, IAM not enforced
Lifecycle (expiration), notifications, replication, Object LockPartial — local behavior only
SSE-S3 / SSE-KMSPartial — headers/metadata only, no real encryption or KMS
S3 SelectPartial — SELECT * FROM S3Object for CSV / JSON Lines
Inventory / analytics configurationPartial

⁠Differences from MinIO

  • No web console (MinIO's port 9001).
  • MINIO_ROOT_USER / MINIO_ROOT_PASSWORD are not recognized; use the DEVCLOUD_S3_* variables above.
  • Do not share the /data volume between multiple containers; locking is in-process only.

⁠Changelog

⁠0.3.0
  • New DEVCLOUD_S3_BUCKETS variable: comma-separated buckets are created before the listener starts. Blank entries are skipped, existing buckets are kept, and an invalid bucket name stops startup with exit code 2.
⁠0.2.0
  • If-None-Match on GET/HEAD: returns 304 Not Modified when the object's ETag matches (* or an ETag list; quoted, unquoted, or weak). It is evaluated before Range and against the requested versionId. The 304 response has no Content-Length.
  • If-None-Match: * on PutObject, CopyObject, and CompleteMultipartUpload: returns 412 PreconditionFailed when a current object exists. Delete markers count as absent. Other values return 501.
  • CopyObject honors x-amz-copy-source-if-none-match against the source ETag.
  • Fix: a conditional write's existence check and write are now atomic with respect to concurrent writes to the same object.
⁠0.1.0
  • Initial standalone image on port 9000 for linux/amd64 and linux/arm64.

Tag summary

Content type

Image

Digest

sha256:d09029731…

Size

27.8 MB

Last updated

3 days ago

docker pull simota/devcloud-s3