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 strategy —
RustfsStorageStrategy, registered with the strategy resolver as aFileStorageStrategyimplementation namedrustfswhen the extension activates, alongside the built-inlocalbackend. - The
FileStorageStrategyinterface 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 throughvectis_sdk.storage): path-style requests ({endpoint}/{bucket}/{key}) signed with AWS Signature Version 4 overhttpx— 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¶
- The extension ships from the
enterprise-extensionsrepo — as an installedvectis-ext-rustfswheel in production, or via theVECTIS_DEV_EXTENSIONSdev-link in development. Enable it for a channel from Settings > Extensions (per-channel activation viaChannelExtension). - 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. - Set
FILE_STORAGE_PROVIDER=rustfsto make it the active backend. - 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
FileStorageStrategyat 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 dailyvectis-gc-media-orphansTemporal schedule (GcMediaOrphansWorkflow), which physically deletes purged media objects through the active backend. - Which backend wins — the
FILE_STORAGE_PROVIDERsetting 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 isS3_PUBLIC_URLwhen set, falling back to the endpoint. A separate public URL matters whenS3_ENDPOINTis an internal Docker hostname (e.g.rustfs:9000) that browsers cannot resolve — which is why the config schema marks it required. Dev compose setsS3_PUBLIC_URL=http://localhost:9000(the S3 API is host-mapped). - Presigned uploads —
generate_presigned_urlreturns a SigV4 query-string presignedPUTURL against the RustFS endpoint; theGET /upload/presignendpoint uses the default 3600-second expiry. - Uploads sign with
UNSIGNED-PAYLOADand 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
localbackend 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.