Files
VoiceStudio/docs/install/docker.md
T
Palash DebnathandClaude Opus 4.8 6306f6edae docs: official Docker Hub image palashdeb/omnivoice-studio (#388)
Link the published Docker Hub repo (https://hub.docker.com/r/palashdeb/
omnivoice-studio) as an official image alongside GHCR in the README install
list and docker.md header. Same images, same tags.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:00:45 +05:30

147 lines
6.7 KiB
Markdown

# OmniVoice Studio — Install with Docker
For headless servers, dedicated GPUs, or "I want one command" deployments.
The docker image bundles the backend; the UI is served over HTTP and you open
it in a normal browser.
**Official images:** [`ghcr.io/debpalash/omnivoice-studio`](https://github.com/debpalash/OmniVoice-Studio/pkgs/container/omnivoice-studio)
and [`palashdeb/omnivoice-studio` on Docker Hub](https://hub.docker.com/r/palashdeb/omnivoice-studio) — same images, same tags.
> **Image ↔ version mapping**
>
> | Tag | What you get |
> |-----|--------------|
> | `:latest` | **Rolling preview** — latest commit on `main` (always one patch ahead of the last release). This is the preview channel; pin `:stable` for production. |
> | `:stable` | Most recent versioned release (updated on every `v*` git tag) |
> | `:0.3.6` | Exact release version |
> | `:0.3` | Latest patch within the 0.3 minor |
> | `:main` | Alias of the same rolling `main` build as `:latest` |
> | `:sha-xxxxxxx` | Specific commit (produced by manual workflow dispatch) |
>
> Versioning rule: `main` always carries *last release + 1 patch*, so `:latest`
> (preview) version-sorts above `:stable` — upgrades flow naturally.
>
> **Note on the update-channel toggle:** The update-channel UI (Settings → About → Update channel) is part of the Tauri desktop app's built-in auto-updater. It does **not** apply to the Docker image — the Docker image is the headless web-server build. To update your Docker deployment, pull the new image tag and recreate the container (`docker compose pull && docker compose up -d`).
## Pull and run (CPU)
```bash
docker pull ghcr.io/debpalash/omnivoice-studio:latest
docker run -d --name omnivoice \
-p 127.0.0.1:3900:3900 \
-v omnivoice-data:/app/omnivoice_data \
-v ~/.cache/huggingface:/root/.cache/huggingface \
ghcr.io/debpalash/omnivoice-studio:latest
```
> **Docker Hub mirror:** the same images are published to
> `palashdeb/omnivoice-studio` on Docker Hub with identical tags — swap the
> image for `palashdeb/omnivoice-studio:latest` if you prefer Docker Hub.
> Tag semantics (`:latest` = rolling main preview, `:stable`/`:X.Y.Z` =
> releases) are the same on both registries.
Open [http://localhost:3900](http://localhost:3900). The first run downloads
~2.4 GB of model weights — follow `docker logs -f omnivoice` to watch.
## Pull and run (NVIDIA GPU)
```bash
docker run -d --name omnivoice --gpus all \
-p 127.0.0.1:3900:3900 \
-v omnivoice-data:/app/omnivoice_data \
-v ~/.cache/huggingface:/root/.cache/huggingface \
ghcr.io/debpalash/omnivoice-studio:latest
```
GPU mode requires the
[NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html)
on the host.
## Docker Compose (recommended)
```bash
# CPU
docker compose -f deploy/docker-compose.yml --profile cpu up -d
# NVIDIA GPU
docker compose -f deploy/docker-compose.yml --profile gpu up -d
```
The `docker-compose.yml` shipped in `deploy/` defaults to `127.0.0.1:3900`
on the host. The backend inside the container binds to `0.0.0.0` so the
host port mapping can forward — the host-side `127.0.0.1` binding is what
enforces loopback-only.
## LAN access
<a id="lan-access"></a>
To expose OmniVoice on your LAN (e.g. you're running it on a homelab box and
opening the UI from a laptop), change the host port mapping:
```yaml
# deploy/docker-compose.yml
services:
omnivoice:
ports:
- "0.0.0.0:3900:3900" # ← was 127.0.0.1:3900:3900
```
The OmniVoice frontend defaults to the **same origin** the page was served
from, so opening the UI from `http://<lan-ip>:3900` Just Works for both the
page load *and* the API/media requests it makes afterwards.
If you front the app with a **reverse proxy** and the API and UI land on
different origins, pin the API base explicitly. Use **`OMNIVOICE_PUBLIC_API_BASE`**
— a *runtime* env var the backend injects into the page, so it works with the
prebuilt image via `docker run -e` (the older `VITE_OMNIVOICE_API` is inlined at
*build* time and cannot be set on a prebuilt image):
```bash
docker run -e OMNIVOICE_PUBLIC_API_BASE=https://api.your-host.example \
-p 0.0.0.0:3900:3900 \
ghcr.io/debpalash/omnivoice-studio:latest
```
> `OMNIVOICE_PUBLIC_API_BASE` must be a plain `http(s)://…` URL; anything else
> is ignored and the app falls back to same-origin. If you build from source you
> may instead bake `VITE_OMNIVOICE_API` at build time, but the runtime var above
> is simpler and image-agnostic.
> **Security:** OmniVoice ships no authentication. Anything on your LAN with
> the URL can use the app. Put it behind a reverse proxy with `basic_auth`
> (Caddy / nginx + htpasswd) or a private network overlay (Tailscale, ZeroTier)
> before exposing publicly.
## Volume mounts
Two paths are worth persisting across container restarts:
| Mount | Purpose | Why |
|-------|---------|-----|
| `omnivoice_data:/app/omnivoice_data` | Project DB, user voices, settings | Survives upgrade; encrypted HF token lives here |
| `~/.cache/huggingface:/root/.cache/huggingface` | HF model cache | Re-using your host's cache saves ~2.4 GB of re-downloads |
## Troubleshooting
- **Container reports 0.2.7 but image is tagged 0.3.x:** This was a workflow bug
(fixes #249, #251) — the `:latest` tag was not being updated on release tag
pushes. Pull the image again after the fix is merged: `docker pull ghcr.io/debpalash/omnivoice-studio:latest`.
The running version is now shown in **Settings → About → Version** (read live
from the backend), so the web UI no longer displays a dash in Docker.
- **Checking which version is running:** `docker exec omnivoice python -c "import importlib.metadata; print(importlib.metadata.version('omnivoice'))"`, or hit the `/health` endpoint — it returns `{"status": "ok", "device": ..., "version": "0.3.x"}`.
- **"Loopback origin required" errors (and a blank version):** the desktop
build restricts the `/system/*` and `/api/settings/*` routes to a loopback
origin, but Docker's NAT makes every request look non-loopback, so the gate
used to 403 the whole admin UI (issue #261). The image now ships with
`OMNIVOICE_SERVER_MODE=1`, which relaxes that gate for the headless
deployment — exposure is instead governed by your `-p` port mapping (keep the
`127.0.0.1:` prefix to stay local) plus the optional share PIN. If you front
the container with your own auth proxy on loopback, set `OMNIVOICE_SERVER_MODE=0`
to re-enable the strict gate.
- **Media-preview 404 in LAN mode:** see the [LAN access](#lan-access) section
above — the `window.location.host` fix shipped in v0.3.
- **GPU not detected:** verify `docker run --rm --gpus all nvidia/cuda:12.8.0-base-ubuntu22.04 nvidia-smi` succeeds first.
- More entries: [docs/install/troubleshooting.md](troubleshooting.md).