The All-in-One image runs a single inference worker across two GPUs. It does
not autoscale or shard across more GPUs or nodes, and it does not ship the
forced aligner, so it serves no word or segment timings. For elastic,
multi-tenant, or higher aggregate throughput deployments, use the Kubernetes
chart, which scales replicas across
all GPUs and nodes. This image is also offline only; there is no
hosted-billing variant of it.
Prerequisites
- A host that meets the All-in-One host requirements.
- Registry access, unless you are loading the image from a transfer archive.
- The image reference from Granted Artifacts in the dashboard.
Load the image
On a host with registry access:Run
Generate a JWT secret once, store it, and reuse the same value on every run. A new value invalidates tokens and sessions issued under the old one.
Everything in the container runs as a non-root user (UID 1000). A fresh named
volume inherits the right ownership; a reused volume or a host bind mount must be
writable by UID 1000.
First start and readiness
On the first cold start the worker compiles its inference graphs and the vocoder builds its engine. Expect roughly ten minutes once the image is on the host, and considerably longer on a fully cold host that also has to transfer the image. Subsequent starts on the same volume take minutes, because both artifacts are cached on the volume.GET /health verifies the speech backend end to end, so it stays unhealthy
through the warmup rather than reporting immediate liveness. Full readiness is a
generation that returns audio:
docker logs -f fish-tts.
Make requests
format values are mp3, wav, pcm, and opus. Optional fields
include reference_id, mp3_bitrate, sample_rate, latency, and
chunk_length.
For the lowest time-to-first-audio, stream over WebSocket at
ws://<host>:8088/v1/tts/live with the same Authorization and model headers,
then send msgpack events: start, one or more text, then stop, and read
audio events until finish. The payloads match the
hosted WebSocket API.
Latency modes
Set it in the request body as
"latency":"balanced", or in the WebSocket start
event.
Reference voices
Reference-id requests resolve only from a local archive. Place one zip per voice at/mnt/shared/reference-archives/<reference_id>.zip, containing audio files at
the zip root each paired with a same-basename .txt transcript. A named Docker
volume has no stable host path, so copy archives in:
/mnt/shared/reference-archives and drop archives into it directly. Then request
with "reference_id":"my-voice".
Authentication and usage
This build records usage to a local, signed, append-only ledger instead of calling a billing service:- Any non-empty
Authorization: Bearertoken is accepted. A missing or empty token returns 401. - The token is recorded verbatim as the billing identity, so use a stable, distinct token per tenant. Two tenants sharing a token are indistinguishable in the ledger.
- The ledger is written under
/mnt/shared/offline-billing-ledger/as signed JSON Lines, one directory per UTC day.
Persistence
Model weights live in the image, not on the volume. Keep
/mnt/shared on
persistent storage: without it, every restart pays the full first-start compile
again and the ledger is lost. The vocoder engine is specific to the GPU model, so
moving to different cards rebuilds it once.
If your platform pins persistent storage somewhere other than /mnt/shared, you
can relocate the three compile caches with COMPILE_CACHE_DIR,
TORCHINDUCTOR_CACHE_DIR, and VQ_CACHE_DIR. Point each at a separate
subdirectory that is writable by UID 1000, and keep the /mnt/shared mount either
way, because reference voices and the ledger always live there.
Capacity
The single worker admits a bounded number of in-flight requests, set byLIMIT_MODEL_CONCURRENCY (default 32); beyond that, requests queue. The ceiling
is bounded by the inference worker’s key-value cache VRAM, so cards with more
memory than the 32 GB baseline can run a higher cap. Raise it at launch without
rebuilding:

