Skip to content

RustFS

RustFS object storage for file uploads, avatars, and media. RustFS is an Apache-2.0, S3-compatible object store written in Rust (a MinIO/Ceph alternative). The extension registers a RustFS-backed implementation of the platform's FileStorageStrategy interface, pointing the shared S3-compatible client (S3Service, SigV4 over httpx) at a self-hosted RustFS endpoint. Core upload surfaces — avatar uploads, media uploads, presigned browser uploads, and the media-orphan purge — then read and write objects in your RustFS bucket. It is the default file-storage backend for local development: docker-compose.yml bundles a rustfs service and sets FILE_STORAGE_PROVIDER=rustfs on the api, worker, and event consumer.

At a glance

Extension id rustfs
Category storage
Version 0.1.0
Provides FileStorageStrategy implementation (registered as rustfs)
External account None (self-hosted RustFS server — endpoint + access/secret key pair)

What It Provides

  • File storage strategyRustfsStorageStrategy, registered with the strategy resolver as a FileStorageStrategy implementation named rustfs when the extension activates, alongside the built-in local backend.
  • The FileStorageStrategy interface covers four operations: upload bytes under a key (returns the public URL), delete an object, build a browser-accessible public URL for a key, and generate a presigned upload URL.
  • The implementation wraps the shared S3Service (re-exported through vectis_sdk.storage): path-style requests ({endpoint}/{bucket}/{key}) signed with AWS Signature Version 4 over httpx — no boto3/aiobotocore dependency. RustFS speaks the same path-style S3 API, so the client is reused unchanged; the strategy differs from MinIO only in provider name and branding.
  • Nothing else — the package contributes no webhook endpoints, Temporal workflows, schedules, admin pages, GraphQL fields, or event subscriptions.

Setup

  1. The extension ships from the enterprise-extensions repo — as an installed vectis-ext-rustfs wheel in production, or via the VECTIS_DEV_EXTENSIONS dev-link in development. Enable it for a channel from Settings > Extensions (per-channel activation via ChannelExtension).
  2. Set the environment variables the manifest's install hint names: S3_ENDPOINT, S3_PUBLIC_URL, S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET — pointed at your RustFS server.
  3. Set FILE_STORAGE_PROVIDER=rustfs to make it the active backend.
  4. Restart the API. The strategy is constructed once, at extension activation, from those application settings.

In the dev compose stack all of this is pre-wired: the bundled rustfs service runs with rustfsadmin / rustfsadmin credentials, and a one-shot rustfs-setup job (the minio/mc image, used purely as an S3 client — RustFS ships no client of its own) creates the vectis-uploads bucket and best-effort sets an anonymous-download policy.

Configuration Reference

Key Type Required Secret Description
s3_endpoint string Yes No RustFS Endpoint
s3_public_url string Yes No Public URL
s3_access_key string Yes No Access Key
s3_secret_key password Yes Yes Secret Key
s3_bucket string Yes No Bucket Name
s3_region string No No Region. Defaults to us-east-1.

password-typed fields are encrypted at rest (Fernet) and masked as *** in the admin configuration form.

Configuration is read from the environment, not the admin form

The activation hook builds the strategy from application settings (environment variables / .env) with the same key names uppercased — S3_ENDPOINT, S3_PUBLIC_URL, S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET, S3_REGION. The extension defines no hot_reload hook, so values saved through the admin configuration form are stored but nothing hands them to the already-registered strategy. Configure via environment variables and restart.

Permissions

The manifest declares no admin permissions (permissions=[]), so no role assignment is needed.

Operational Notes

  • Who calls it — core resolves the active FileStorageStrategy at call time for avatar uploads (POST /api/upload/avatar), media uploads (POST /upload), presigned upload URLs (GET /upload/presign), CMS image derivative generation, and the daily vectis-gc-media-orphans Temporal schedule (GcMediaOrphansWorkflow), which physically deletes purged media objects through the active backend.
  • Which backend wins — the FILE_STORAGE_PROVIDER setting pins the active backend by name (rustfs, s3, minio, local, ...). When it is empty, the most recently registered implementation wins (legacy behavior); a configured name that isn't registered falls back to last-registered with a warning rather than failing uploads.
  • Public URLs are path-style: <base>/<bucket>/<key>, where the base is S3_PUBLIC_URL when set, falling back to the endpoint. A separate public URL matters when S3_ENDPOINT is an internal Docker hostname (e.g. rustfs:9000) that browsers cannot resolve — which is why the config schema marks it required. Dev compose sets S3_PUBLIC_URL=http://localhost:9000 (the S3 API is host-mapped).
  • Presigned uploadsgenerate_presigned_url returns a SigV4 query-string presigned PUT URL against the RustFS endpoint; the GET /upload/presign endpoint uses the default 3600-second expiry.
  • Uploads sign with UNSIGNED-PAYLOAD and a 60-second HTTP timeout; deletes treat a 404 as success (idempotent) with a 30-second timeout.
  • Avatar uploads fall back to the built-in local backend when the primary backend raises, so an unreachable RustFS degrades rather than hard-fails that endpoint.
  • The S3-compatible storage extensions — Amazon S3, MinIO, RustFS, and DigitalOcean Spaces — all read the same S3_* settings; configure the one that matches your provider. See also Storage Extensions in the developer guide.