Skip to main content
The offline delivery forms run with no outbound network access at all: model assets are served from inside the deployment and usage is recorded to a local signed ledger rather than a billing service. Getting there takes one preparation step — moving the artifacts across the air gap — and one verification step. Everything below runs on a connected staging machine first, then on the disconnected side. Only the staging machine needs registry access.

Mirror container images

On the connected machine, derive the image list from the chart you are about to install, so the list always matches the release:
Review images.txt, then pull and pack the images. zstd keeps the transfer archive small; gzip works too if zstd is not available on both sides.
For the All-in-One image the same pattern applies with a single reference:
Transfer fish-audio-images.tar.zst, images.txt, the chart archive from ./transfer/, and your values file across the air gap by whatever means your policy allows.

Load on the disconnected side

For a Kubernetes install, push the loaded images into the registry your cluster can reach:
Then point the chart at your mirror by overriding each component’s image.repository in your values file, and confirm nothing still refers to an external host before you install:
Install from the local chart archive exactly as described in Kubernetes deployment, substituting the archive path for the chart reference. The chart archive is self-contained, so no chart repositories are contacted during the install. For the All-in-One container, the loaded image is all you need — continue with Run.

Model assets offline

The offline forms never download model weights at runtime. Two things still come from you rather than from the network:
  • Reference voices. Stage the archives yourself, as described in Kubernetes deployment or All-in-One. This behavior is identical online and offline.
  • Timestamp alignment. The forced aligner is not part of the offline bundle. Contact Fish Audio if your air-gapped deployment needs word or segment timings.

Offline usage accounting

With no billing service to call, the deployment records every charge to a local, signed, append-only ledger on persistent storage. No request is ever rejected for billing reasons, and the record is tamper-evident and independently verifiable.

How tokens behave

  • Any non-empty Authorization: Bearer token is accepted. Empty or missing still returns 401.
  • The token is recorded verbatim as the billing identity, so choose a stable, distinct value per tenant. Tenants that share a token cannot be told apart in the ledger.

Disk layout

Files are grouped one directory per UTC day, so a day archives by copying a single directory:
Each file is written by exactly one process, so replicas never interleave into the same file even though they share the directory. Every file is an independent hash chain: a new day, a restart, or a new replica starts a new file.

Record format

Each line is one record: a shared envelope plus a payload chosen by event_type (process_started, heartbeat, billing_event, process_stopping). Charges accumulate in Redis per token, product, and backend, and a background task flushes them roughly once a minute as one aggregated billing_event per bucket. A failed write is retried rather than dropped. When a file is finished it is sealed into a matching signed manifest carrying the last record’s hash and signature, the record counts, and the file’s totals. Sealing is automatic: yesterday’s file is sealed shortly after the UTC day rolls over, and a graceful shutdown seals the current one. Today’s in-progress file has no manifest yet.

Verify the ledger

Verification needs only the public key that Fish Audio supplies, plus jq and openssl:
Verified OK confirms the record is authentic. Recompute the hash itself from the record body and compare it to the record_hash field:
A full audit additionally checks that seq is contiguous, that each prev_hash links the previous record, that the manifest signature verifies, and that the manifest totals match the event file. Ask Fish Audio for the verification script that runs all of these over a ledger directory.
The ledger is tamper-evident: signature and hash-chain checks reliably detect corruption and modification of the files. If your audit requirements call for stronger guarantees, such as an independent write-once anchor or a separately administered audit sink, raise it with Fish Audio so it can be designed into the deployment.

Retention and reconciliation

  • The ledger lives on persistent shared storage and survives restarts and rescheduling.
  • Nothing prunes it. Archive completed day directories to your own storage on your retention schedule, and never delete the live directory out from under a running instance.
  • Usage is reconciled afterwards from the signed day directories, on the cadence set in your agreement. Copy whole directories, including the manifests, so the totals can be verified independently.

Prove there is no egress

Configuration review is not proof. Demonstrate it.

Kubernetes

Deny external egress for the namespace, keeping in-cluster traffic and DNS, then confirm the deployment still generates audio.
deny-external-egress.yaml
Re-run the smoke test. It must still return playable audio. This proves nothing unless your CNI actually enforces NetworkPolicy, so confirm enforcement with a deliberate control: exec into a pod in the namespace and check that an outbound request fails.

All-in-One

The strongest proof is a container that never had a network interface, on a fresh volume, so nothing could have been fetched even during the first compile:
With --network none no host port can be published, so drive the request from inside the container once the cold start finishes:
A 200 with a non-trivial audio file is the proof. A weaker but faster variant disconnects an already-warmed container from every Docker network and repeats the request; it demonstrates that the running service survives losing the network, but not that the cold start never needed it. Capture the output of whichever check you run as deployment evidence.