Skip to content
You are reading the docs for Backstory 0.2 (private beta). Behavior may change before general availability; the changelog lists every change.

Self-hosting overview

Backstory ships as one Helm chart, plus a single-virtual-machine install for a pilot. Recordings, exports, and attachments sit in an object store. The app servers do not hold them.

InstallYou provideRecordings live onMinimum
externalPostgres 16 with pgvector, ClickHouse 24.8+, and a store. Valkey and LiveKit if you want Live AssistThe bucket you bring. The Backstory nodes stay small2 nodes × 4 vCPU / 8 GB for the Backstory pods
bundledA Kubernetes cluster with a default StorageClassMinIO, on its own volume, separate from Postgres and ClickHouse1 node × 8 vCPU / 32 GB, 500 GB SSD. 16 GB is the hard floor
single VMOne machine with DockerMinIO on that machine’s disk8 vCPU / 32 GB / 500 GB. 16 GB is the hard floor

An air-gapped install is whichever of those it sits on, with images from your own registry. The chart also has a saas profile, which is Backstory’s own cloud. Capacity past these floors is on Sizing and retention.

The chart or the virtual-machine env file only carries a starting store. After install, the instance owner opens Storage setup in the account menu and chooses Amazon Web Services, Google Cloud, Microsoft Azure, or the store on this install (MinIO, Ceph, or the bundled disk). Saving there replaces the starting store. The API, gateway, and worker pick it up within a minute.

Google Cloud uses the access key and secret from Cloud Storage, under Interoperability. Azure uses the storage account, account key, and container. On Amazon, a role on the machine can sign for recordings and exports. Recorded call audio still needs a key, because that upload runs in a separate process.

Cluster backups stay in the chart (bundled.backups, bucket backstory-backups). That screen does not change them.

Terminal window
helm dependency update deploy/helm/backstory
helm upgrade --install backstory deploy/helm/backstory -n backstory --create-namespace \
-f deploy/helm/backstory/values-bundled.yaml --set bundled.acknowledgeSizing=true
# once the operators are running:
helm upgrade backstory deploy/helm/backstory -n backstory \
-f deploy/helm/backstory/values-bundled.yaml --set bundled.acknowledgeSizing=true --set bundled.createClusters=true

Set datastores.postgres.urlSecret, datastores.clickhouse.addr, and datastores.s3.* in your values file and install with profile: external. Those S3 settings are the starting store. Amazon, Google Cloud, Azure, MinIO, Ceph, and NetApp StorageGRID are chosen afterward in Storage setup.

From deploy/selfhosted:

Terminal window
cp .env.selfhosted.example .env
# edit .env: domain, master key, and the generated passwords
docker compose -f docker-compose.selfhosted.yml --env-file .env up -d

This is one machine, with no extra replicas. Use the Helm chart for anything past a pilot.

Every Backstory pod runs with requests equal to limits and GOMEMLIMIT at 85% of the limit. The gateway holds at most one chunk per connection; backlog stays in browsers. Datastores must never share a memory limit with application pods.

helm upgrade with the new chart version. Database migrations are expand-and-contract and run automatically on worker start; rollbacks are safe within one minor version.

Per-project retention is in days for replays, events, and aggregates. On Amazon and on a store on this install, expiry is a lifecycle rule keyed on the retention-class object tag, plus a daily cleanup. On Google Cloud and Azure, the daily cleanup deletes expired objects.