---
sidebar_position: 4
title: Storage
---

# Storage

A self-hosted box keeps two stateful stores, both as single-box containers on named docker volumes:

- **ScyllaDB Alternator** (`zibby-scylla`, volume `scylla-data`) — the DynamoDB-compatible metadata store. All accounts, projects, agents, integrations, executions, and stores live here.
- **Object store** (`zibby-minio`, volume `seaweed-data` or legacy `minio-data`) — run sources, artifacts, per-node logs, datasets, and marketplace icons, over the S3 API.

Both survive `docker compose restart` / `down` (they're on named volumes) but **not** `down -v`. Back them up — see [Backup & restore](./backup-restore).

## MinIO → SeaweedFS

MinIO's upstream was archived in 2026-04, so as of **0.1.126** the object store is **SeaweedFS**. The service is still *named* `minio` in compose and DNS so every `S3_ENDPOINT` consumer is unchanged — only the engine behind it changed. (Full evaluation: `strategy/object-store-replacement.md` in the root repo.)

- **New installs** come up on SeaweedFS (volume `seaweed-data`). Nothing to do.
- **Upgrades from a MinIO box auto-migrate.** When the installer upgrades a legacy (pre-flip, `minio-data`) box, it keeps MinIO running for that `up`, then — once the upgraded stack is healthy — runs the migration automatically.

### How the auto-migration works

It is designed to **auto-attempt, never auto-brick** — MinIO's data is never modified, so every failure path rolls back to a working box:

1. **backup** — a full `backup.sh` snapshot first; it refuses to migrate without one.
2. **quiesce** — stop the S3 writers (control-plane + copilot-runtime) so the copy is consistent.
3. **copy + verify** — `migrate-object-store.sh` mirrors every bucket into a throwaway SeaweedFS container writing to the `seaweed-data` volume, then verifies per-bucket **object count + total bytes must match exactly**, plus a sha256 comparison of sampled objects (always including the largest). It never deletes anything.
4. **flip** — record `ZIBBY_OBJECT_STORE=seaweedfs` in `.env` and bring up the default (SeaweedFS) stack.
5. **health-gate** — the new control plane must become healthy **and** pass an authenticated S3 list against the migrated store.
6. **rollback** — any failure at any stage rolls back to MinIO (whose data was never touched) with a loud status line.

The **old `minio-data` volume is retained** as a rollback safety net. After a few days of verified operation you can reclaim it:

```bash
docker volume rm <project>_minio-data   # irreversible — only after you trust SeaweedFS
```

### Controlling / retrying the migration

- **Opt out** (stay on MinIO for now): run the installer with `ZIBBY_SKIP_OBJECT_STORE_MIGRATION=1`.
- **Retry** after a failed auto-migration: re-run the installer, or manually —
  ```bash
  cd zibby-selfhosted
  docker compose stop control-plane copilot-runtime
  bash migrate-object-store.sh --yes
  # then flip: set ZIBBY_OBJECT_STORE=seaweedfs + COMPOSE_FILE=docker-compose.yml in .env
  docker compose -f docker-compose.yml up -d
  ```
- **MinIO emergency fallback image** (if a legacy box lost its local MinIO image): the pinned tarball is at `https://dl.zibby.app/selfhosted/infra/` — verify the `.sha256`, then `docker load -i`. The box only ever pulls images from our own CDN, never a third-party registry.
