Skip to main content
Both Helm delivery forms use the same chart and the same procedure. They differ only in how usage is accounted, which is expressed in your values file.

Prerequisites

  • A cluster that meets the requirements, preferably a clean cluster dedicated to this deployment.
  • Shared storage mounted at the same path on every node.
  • Registry access configured, and a chart version chosen on the Self Host page — see Releases.
  • Prometheus installed, or approved for installation.
  • Reference voice archives prepared, if your traffic uses reference_id.
Set the values you will reuse:
fish-audio is the supported default namespace. If you must use a different one, change both the Helm --namespace argument and MODEL_DISCOVERY_NAMESPACE in your values file. Otherwise the edge API looks for the model services in the wrong namespace.

Choose a delivery form

“Offline” here means runtime-offline. Installation still pulls images and the chart from a registry. For an install with no network at all, see Air-gapped deployments.

Preflight

Verify on every node that the shared storage path is a real network mount, not a local directory, and that it is writable. Both matter and they fail differently: a node missing the mount quietly gets a local directory and looks healthy while data splits across nodes, and a read-only export stops every Pod before it starts, because Kubernetes creates directories on the volume for each workload. With node access, findmnt -T /mnt/share should report an nfs or nfs4 filesystem. Without node access:

Create the namespace and secrets

The chart expects three existing secrets. The registry pull secret is created in Registry access. Create the other two:
For production, prefer External Secrets, Sealed Secrets, or your cloud secret manager over plain Kubernetes Secrets.

Prepare a values file

The chart carries a values file for each delivery form under profiles/, so pulling the chart gets you a starting point:
Edit the copy. A later helm pull --untar fails rather than overwriting the directory it created, so upgrading means deleting it first. A profile sets the deployment mode and the shared-storage path. What a cluster usually has to change: Image references are pinned in the chart. Change them only when mirroring into your own registry, as Air-gapped deployments describes — a version is otherwise selected with --version, not by editing tags. Talk to your account team before changing replica counts. The profiles ship the single-worker shape the delivery was sized against, and the API, GPU, aligner, normalizer and router deployments read a replica change in a values file on install but not on helm upgrade, where the running count wins. oxidengine, the model warehouse and Redis are the other way round: they take the value every time, so a kubectl scale on those is undone by the next upgrade. Ingress and TLS are disabled by default. Enable them only if you want Kubernetes to manage your access layer; otherwise put your own ingress controller or load balancer in front of the edge-api-production service.

Install Prometheus

The chart exposes metrics through prometheus.io/* pod annotations and creates no ServiceMonitors. An annotation-scraping Prometheus works out of the box:
If you already run kube-prometheus-stack, add an annotation-based scrape config instead.

Stage reference voices

A self-hosted deployment never downloads reference audio from the network. Requests that pass a reference_id resolve from Redis, then from a local archive on shared storage. Stage one zip per voice before enabling that traffic:
Each archive holds one or more audio files at the zip root, each paired with a UTF-8 .txt transcript of the same basename:
Supported audio extensions are .wav, .mp3, and .opus. Do not nest directories inside the archive, and do not add prefixes to the filename — the file name must match the reference id exactly. If you have no node shell, stage archives through a helper pod that mounts the share, then confirm the edge API can see the file:
These archives are durable data, not cache. Back them up and preserve the path across upgrades.

Validate the release

Render the manifests before touching the cluster:

Install

Wait for readiness

On the first install the inference worker compiles its GPU graphs and the vocoder builds its inference engine, which takes far longer than later rollouts. Wait on every workload in the release, Deployments and StatefulSets alike:
The timeout applies per workload, not to the loop. Watch progress with:

Smoke test

The acceptance signal is a successful generation, not a health probe. With no ingress configured, port-forward the edge API:
The test passes when the request returns HTTP 200 and the file contains playable audio. Also confirm that the GPU workloads see the shared storage mount, that Redis is ready, that reference archives are visible if you use them, and that no pod is in a crash or image-pull loop.

Upgrade

If the helm-diff plugin is not installed, review helm template output before applying. Re-run the smoke test after every upgrade and keep the previous revision available until the deployment is accepted.

Roll back

Uninstall

Uninstall does not remove data on shared storage. Reference archives, the usage ledger, and compile caches survive and should be deleted deliberately.

Next steps