Add Docker deployment with Caddy HTTPS reverse proxy

CPU-only torch image (~180MB vs 873MB CUDA), PipeWire socket
passthrough for audio playback, SNAC HuggingFace cache volume.
Served at voice.l.supported.systems via caddy-docker-proxy.
This commit is contained in:
Ryan Malloy 2026-02-20 20:47:22 -07:00
parent 2fd84f0df7
commit c53db4b251
3 changed files with 105 additions and 0 deletions

41
Dockerfile Normal file
View File

@ -0,0 +1,41 @@
FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim
# PipeWire client tools — pw-play connects to the host's PipeWire socket
RUN apt-get update && apt-get install -y --no-install-recommends \
pipewire-bin \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
ENV UV_COMPILE_BYTECODE=1
# Create venv
RUN uv venv
# Install CPU-only torch first (saves ~3GB vs CUDA — SNAC runs on CPU anyway)
RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install torch --index-url https://download.pytorch.org/whl/cpu
# Install project dependencies (torch already satisfied, won't redownload)
COPY pyproject.toml ./
RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install --no-deps -r pyproject.toml 2>/dev/null || true
# Copy source and install project
COPY src/ src/
RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install .
# Non-root user matching host uid for PipeWire socket access
RUN useradd -u 1000 -m tts \
&& mkdir -p /home/tts/.cache/huggingface \
&& chown -R tts:tts /home/tts/.cache
USER tts
ENV PATH="/app/.venv/bin:$PATH"
EXPOSE 8371
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s \
CMD python -c "import socket; s=socket.create_connection(('127.0.0.1',8371),2); s.close()" || exit 1
CMD ["tts-mcp"]

28
Makefile Normal file
View File

@ -0,0 +1,28 @@
include .env
export
.PHONY: build up down logs restart status
build:
docker compose build
up: build
docker compose up -d
@sleep 2
docker compose logs --tail 20
down:
docker compose down
logs:
docker compose logs -f
restart:
docker compose restart
@sleep 2
docker compose logs --tail 20
status:
@docker compose ps
@echo "---"
@curl -s http://localhost:8371/mcp 2>/dev/null | head -5 || echo "Server not responding"

36
docker-compose.yml Normal file
View File

@ -0,0 +1,36 @@
services:
tts-mcp:
build: .
container_name: tts-mcp
restart: unless-stopped
env_file: .env
environment:
# Override for Docker networking (container DNS instead of IPs)
TTS_PIPER_HOST: piper-tts
TTS_OLLAMA_URL: http://host.docker.internal:11434
# PipeWire client config
XDG_RUNTIME_DIR: /run/user/1000
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
# Kokoro ONNX models (read-only)
- ./models:/app/models:ro
# HuggingFace cache for SNAC model download
- hf-cache:/home/tts/.cache/huggingface
# PipeWire socket for audio playback through host speakers
- /run/user/1000/pipewire-0:/run/user/1000/pipewire-0
networks:
- caddy
- dootie-internal
labels:
caddy: voice.l.supported.systems
caddy.reverse_proxy: "{{upstreams 8371}}"
volumes:
hf-cache:
networks:
caddy:
external: true
dootie-internal:
external: true