A self-hostable web console for browsing and managing buckets and objects on any S3-compatible storage endpoint — MinIO, Cloudflare R2, Backblaze B2, Ceph RGW, Wasabi, AWS S3, or any other backend that speaks the S3 API. Sign in via OIDC, save one or more connection profiles (endpoint + credentials, encrypted at rest), then browse, upload, download, preview, share, and manage buckets across all of them from one UI.
Everything runs as a single Node process: the server serves the API under /api, OIDC
routes under /auth, and the built frontend as static files, all from one origin.
Full documentation, including the environment variable reference, OIDC provider walkthroughs, the Kubernetes/Helm guide, and security notes, is published at tinyorbitvn.github.io/orbit-object-console.
Browsing objects, with the metadata and preview pane on the selected file:
Buckets across the active connection, with scan-based object counts and sizes:
Connection profiles, with presets for the common S3-compatible backends:
Usage, computed from on-demand bucket scans:
Dark theme — appearance, branding and format defaults are stored per user:
In-browser preview works for images, text, PDF, video and audio:
Requires Node 22+ (or Docker).
-
Generate an encryption key. Profile secret access keys are encrypted at rest with this key (AES-256-GCM, 32 bytes). Generate one and keep it safe:
openssl rand -hex 32
-
Register an OIDC client. Orbit has no local passwords — sign-in is always via an external OIDC provider (Authorization Code + PKCE). The redirect URI is always
<origin>/auth/callback, e.g.http://localhost:3000/auth/callbackin dev orhttps://storage.example.com/auth/callbackin production. See the OIDC setup guide for worked examples with Keycloak and Google (any standards-compliant provider works the same way). -
Choose a database. SQLite is the default — no setup, data lands in
./data/app.db(override withSQLITE_PATH). SetDATABASE_URLto a PostgreSQL connection string to use Postgres instead; migrations run automatically for whichever driver is active. -
Run it.
With Docker Compose (also starts a local MinIO for storage):
export ENCRYPTION_KEY=$(openssl rand -hex 32) export OIDC_ISSUER_URL=... OIDC_CLIENT_ID=... OIDC_CLIENT_SECRET=... export OIDC_REDIRECT_URI=http://localhost:3000/auth/callback docker compose up --build
Or directly with Node:
npm ci npm run build ENCRYPTION_KEY=... OIDC_ISSUER_URL=... OIDC_CLIENT_ID=... OIDC_CLIENT_SECRET=... \ OIDC_REDIRECT_URI=http://localhost:3000/auth/callback \ npm start
Then sign in, add a connection profile pointing at your storage endpoint, and browse.
Released images are published to the GitHub Container Registry on every v* tag:
docker pull ghcr.io/tinyorbitvn/orbit-object-console:latest
# or pin a version
docker pull ghcr.io/tinyorbitvn/orbit-object-console:0.2.2docker run -p 3000:3000 -v "$PWD/data:/app/data" \
-e ENCRYPTION_KEY=... \
-e OIDC_ISSUER_URL=... -e OIDC_CLIENT_ID=... -e OIDC_CLIENT_SECRET=... \
-e OIDC_REDIRECT_URI=http://localhost:3000/auth/callback \
ghcr.io/tinyorbitvn/orbit-object-console:latestThe image bundles the built frontend and runs the single Node process. Mount
/app/data to persist the SQLite database, or set DATABASE_URL for Postgres.
A Helm chart lives in charts/orbit-object-console.
It follows the Bitnami chart conventions — same values layout, resource presets,
probe overrides, security defaults and extraDeploy hooks — but keeps its helpers
local, so there are no chart dependencies to fetch before installing.
helm install orbit ./charts/orbit-object-console \
--namespace orbit --create-namespace \
--set oidc.issuerUrl=https://id.example.com/realms/main \
--set oidc.clientId=orbit-console \
--set oidc.clientSecret=<client-secret> \
--set ingress.enabled=true \
--set ingress.hostname=orbit.example.comThe redirect URI is derived from the ingress hostname when ingress.enabled=true;
otherwise set oidc.redirectUri explicitly. By default the console stores its data
in SQLite on a PersistentVolumeClaim — for more than one replica, point it at
PostgreSQL with externalDatabase.enabled=true. The chart also supports keyless AWS
IAM authentication (EKS Pod Identity / IRSA) via awsKeyless.enabled — see the
Kubernetes guide
for details and its shared-identity caveat.
If you do not supply an encryption key, the chart generates one on first install and reuses it on upgrades. Back it up: losing it makes stored connection secrets undecryptable and users must re-enter their storage credentials.
Renamed chart. The chart was renamed from
s3-object-clienttoorbit-object-console; this renames the underlying Kubernetes resources, so an existing release must be installed fresh rather than upgraded in place. See the Kubernetes guide for the full rename note.v0.1.xartifacts remain published under the old chart and image names; only new tags carryorbit-object-console.
See the chart README for the full parameter reference.
Orbit is configured entirely through environment variables (OIDC provider settings,
ENCRYPTION_KEY, database, AWS_KEYLESS_ENABLED, ...), validated on startup. See the
full configuration reference
for the complete table.
No local passwords (OIDC-only sign-in), profile secrets encrypted at rest with
ENCRYPTION_KEY (losing or rotating it makes stored secrets undecryptable and
requires re-entering credentials), a per-profile verify-TLS toggle, and presigned
share links that point directly at the storage endpoint rather than through Orbit
(so recipients must be able to reach it). See the full
security guide
for details, including the shared-identity caveat for keyless AWS IAM profiles.
Start a local MinIO for storage (and, optionally, Postgres):
docker compose up minio
# or: docker compose --profile postgres up minio postgresRun tests:
npm test # both workspaces (server + web)
npm test -w server
npm test -w webServer tests are split into two layers:
server/test/*.test.ts— unit tests (config, crypto, auth, routing, static serving, ...), no external services required. Run withnpm run test:unit -w server.server/test/integration/*.test.ts— exercise real S3 semantics against the MinIO container started above (buckets, objects, copy/move, sharing, scanning, ...).npm test -w serverruns both layers and requires MinIO to be reachable atlocalhost:9000.
Out of scope for this release (see the design spec, §8):
- No access-keys management page (would need per-backend admin APIs).
- No request/egress analytics (not exposed by the S3 API).
- No object versioning browser — versioning can be toggled on a bucket, but browsing or restoring old versions is deferred.
- No multi-user sharing of profiles, roles, or permissions — no admin UI; every signed-in user manages their own profiles independently, and bucket settings and branding are shared read/write across all users.
- No editing of region/storage-class/encryption defaults on the bucket General tab — those are display-only where the underlying S3 API has no generic write path.





