Bucketrb
Bucketrb is a small local S3-compatible server for Ruby development and test
environments. It is intentionally narrower than MinIO or LocalStack: it focuses
on the S3 API surface commonly used by Rails apps, aws-sdk-s3, ActiveStorage
adjacent integrations, and browser direct uploads.
Status
This project is an early MVP. It currently implements:
- path-style S3 requests
- unsigned and presigned
GET,HEAD,PUT,POST, andDELETE CreateBucketandHeadBucketGetObject,HeadObject,PutObject,CopyObject, andDeleteObjectListObjectsandListObjectsV2DeleteObjects- browser-style presigned POST multipart uploads
- object metadata through
x-amz-meta-* - filesystem persistence
- permissive CORS for local browser uploads
It does not currently implement S3 authorization, bucket policies, ACL semantics, multipart upload APIs, object versioning, lifecycle rules, virtual host-style bucket addressing, or service APIs outside S3.
See ROADMAP.md for planned work and explicit non-goals.
Install
From a local checkout:
bundle install
bundle exec exe/bucketrb serve --root ./data --bucket my-bucket
After release:
gem install bucketrb
bucketrb serve --root ./data --bucket my-bucket
CLI
bucketrb serve \
--host 127.0.0.1 \
--port 4566 \
--root ./data/bucketrb \
--bucket app-dev-bucket
Options:
--host HOST: bind host. Default:127.0.0.1--port PORT: bind port. Default:4566--root PATH: filesystem storage root. Default:data/bucketrb--bucket NAME: create a bucket at startup. May be repeated.--buckets-from-env: create buckets from environment variables ending in_BUCKETor_S3_BUCKET
Ruby SDK Example
require "aws-sdk-s3"
client = Aws::S3::Client.new(
endpoint: "http://127.0.0.1:4566",
region: "ap-northeast-1",
access_key_id: "bucketrb",
secret_access_key: "bucketrb",
force_path_style: true
)
client.create_bucket(bucket: "example")
client.put_object(bucket: "example", key: "hello.txt", body: "hello")
puts client.get_object(bucket: "example", key: "hello.txt").body.read
Docker
Build locally:
docker build -t bucketrb .
docker run --rm -p 4566:4566 -v "$PWD/data:/data" \
-e APP_S3_BUCKET=app-dev-bucket \
bucketrb
Migration Sketch
An application that currently uses a local S3 emulator can run Bucketrb on the same local port and point its S3 SDK configuration at that endpoint:
services:
bucketrb:
image: bucketrb:latest
ports:
- 127.0.0.1:${S3_EMULATOR_PORT:-4566}:4566
environment:
- AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:-ap-northeast-1}
- APP_S3_BUCKET=${APP_S3_BUCKET:-app-dev-bucket}
- PUBLIC_ASSETS_BUCKET=${PUBLIC_ASSETS_BUCKET:-public-assets-dev}
- PRIVATE_FILES_BUCKET=${PRIVATE_FILES_BUCKET:-private-files-dev}
volumes:
- ./data/bucketrb:/data:delegate
For aws-sdk-s3, use path-style addressing:
endpoint: ENV.fetch("S3_ENDPOINT", "http://127.0.0.1:4566")
force_path_style: true
Test
ruby -Ilib:test test/bucketrb/object_store_test.rb
ruby -Ilib:test test/bucketrb/s3_contract_test.rb
The contract test starts a localhost HTTP server and exercises it through
aws-sdk-s3.