mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2026-03-21 22:56:47 +00:00
* fix: local processing instead of http server for cpu * add fallback token if service worker doesnt work * chore: rename processors to keep processor pattern up to date and allow other processors to be createed and used with env vars
398 lines
12 KiB
YAML
398 lines
12 KiB
YAML
# Self-hosted production Docker Compose — single file for everything.
|
|
#
|
|
# Usage: ./scripts/setup-selfhosted.sh <--gpu|--cpu|--hosted> [--ollama-gpu|--ollama-cpu] [--garage] [--caddy]
|
|
# or: docker compose -f docker-compose.selfhosted.yml [--profile gpu] [--profile ollama-gpu] [--profile garage] [--profile caddy] up -d
|
|
#
|
|
# ML processing modes (pick ONE — required):
|
|
# --gpu NVIDIA GPU container for transcription/diarization/translation (profile: gpu)
|
|
# --cpu In-process CPU processing on server/worker (no ML container needed)
|
|
# --hosted Remote GPU service URL (no ML container needed)
|
|
#
|
|
# Local LLM (optional — for summarization/topics):
|
|
# --profile ollama-gpu Local Ollama with NVIDIA GPU
|
|
# --profile ollama-cpu Local Ollama on CPU only
|
|
#
|
|
# Daily.co multitrack processing (auto-detected from server/.env):
|
|
# --profile dailyco Hatchet workflow engine + CPU/LLM workers
|
|
#
|
|
# Other optional services:
|
|
# --profile garage Local S3-compatible storage (Garage)
|
|
# --profile caddy Reverse proxy with auto-SSL
|
|
#
|
|
# Prerequisites:
|
|
# 1. Run ./scripts/setup-selfhosted.sh to generate env files and secrets
|
|
# 2. Or manually create server/.env and www/.env from the .selfhosted.example templates
|
|
|
|
services:
|
|
# ===========================================================
|
|
# Always-on core services (no profile required)
|
|
# ===========================================================
|
|
|
|
server:
|
|
build:
|
|
context: ./server
|
|
dockerfile: Dockerfile
|
|
image: monadicalsas/reflector-backend:latest
|
|
restart: unless-stopped
|
|
ports:
|
|
- "127.0.0.1:1250:1250"
|
|
- "51000-51100:51000-51100/udp"
|
|
env_file:
|
|
- ./server/.env
|
|
environment:
|
|
ENTRYPOINT: server
|
|
# Docker-internal overrides (always correct inside compose network)
|
|
DATABASE_URL: postgresql+asyncpg://reflector:reflector@postgres:5432/reflector
|
|
REDIS_HOST: redis
|
|
CELERY_BROKER_URL: redis://redis:6379/1
|
|
CELERY_RESULT_BACKEND: redis://redis:6379/1
|
|
# ML backend config comes from env_file (server/.env), set per-mode by setup script
|
|
# HF_TOKEN needed for in-process pyannote diarization (--cpu mode)
|
|
HF_TOKEN: ${HF_TOKEN:-}
|
|
# WebRTC: fixed UDP port range for ICE candidates (mapped above)
|
|
WEBRTC_PORT_RANGE: "51000-51100"
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
volumes:
|
|
- server_data:/app/data
|
|
|
|
worker:
|
|
build:
|
|
context: ./server
|
|
dockerfile: Dockerfile
|
|
image: monadicalsas/reflector-backend:latest
|
|
restart: unless-stopped
|
|
env_file:
|
|
- ./server/.env
|
|
environment:
|
|
ENTRYPOINT: worker
|
|
DATABASE_URL: postgresql+asyncpg://reflector:reflector@postgres:5432/reflector
|
|
REDIS_HOST: redis
|
|
CELERY_BROKER_URL: redis://redis:6379/1
|
|
CELERY_RESULT_BACKEND: redis://redis:6379/1
|
|
# ML backend config comes from env_file (server/.env), set per-mode by setup script
|
|
HF_TOKEN: ${HF_TOKEN:-}
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
volumes:
|
|
- server_data:/app/data
|
|
|
|
beat:
|
|
build:
|
|
context: ./server
|
|
dockerfile: Dockerfile
|
|
image: monadicalsas/reflector-backend:latest
|
|
restart: unless-stopped
|
|
env_file:
|
|
- ./server/.env
|
|
environment:
|
|
ENTRYPOINT: beat
|
|
DATABASE_URL: postgresql+asyncpg://reflector:reflector@postgres:5432/reflector
|
|
REDIS_HOST: redis
|
|
CELERY_BROKER_URL: redis://redis:6379/1
|
|
CELERY_RESULT_BACKEND: redis://redis:6379/1
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
|
|
web:
|
|
build:
|
|
context: ./www
|
|
dockerfile: Dockerfile
|
|
image: monadicalsas/reflector-frontend:latest
|
|
restart: unless-stopped
|
|
ports:
|
|
- "127.0.0.1:3000:3000"
|
|
env_file:
|
|
- ./www/.env
|
|
environment:
|
|
NODE_ENV: production
|
|
NODE_TLS_REJECT_UNAUTHORIZED: "0"
|
|
SERVER_API_URL: http://server:1250
|
|
KV_URL: redis://redis:6379
|
|
KV_USE_TLS: "false"
|
|
NEXTAUTH_URL_INTERNAL: http://localhost:3000
|
|
depends_on:
|
|
- redis
|
|
|
|
redis:
|
|
image: redis:7.2-alpine
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 30s
|
|
timeout: 3s
|
|
retries: 3
|
|
volumes:
|
|
- redis_data:/data
|
|
|
|
postgres:
|
|
image: postgres:17-alpine
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: reflector
|
|
POSTGRES_PASSWORD: reflector
|
|
POSTGRES_DB: reflector
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
- ./server/docker/init-hatchet-db.sql:/docker-entrypoint-initdb.d/init-hatchet-db.sql:ro
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U reflector"]
|
|
interval: 30s
|
|
timeout: 3s
|
|
retries: 3
|
|
|
|
# ===========================================================
|
|
# Specialized model containers (transcription, diarization, translation)
|
|
# Only the gpu profile is activated by the setup script (--gpu mode).
|
|
# The cpu service definition is kept for manual/standalone use but is
|
|
# NOT activated by --cpu mode (which uses in-process local backends).
|
|
# Both services get alias "transcription" so server config never changes.
|
|
# ===========================================================
|
|
|
|
gpu:
|
|
build:
|
|
context: ./gpu/self_hosted
|
|
dockerfile: Dockerfile
|
|
profiles: [gpu]
|
|
restart: unless-stopped
|
|
ports:
|
|
- "127.0.0.1:8000:8000"
|
|
environment:
|
|
HF_TOKEN: ${HF_TOKEN:-}
|
|
volumes:
|
|
- gpu_cache:/root/.cache
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: all
|
|
capabilities: [gpu]
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8000/docs"]
|
|
interval: 15s
|
|
timeout: 5s
|
|
retries: 10
|
|
start_period: 120s
|
|
networks:
|
|
default:
|
|
aliases:
|
|
- transcription
|
|
|
|
cpu:
|
|
build:
|
|
context: ./gpu/self_hosted
|
|
dockerfile: Dockerfile.cpu
|
|
profiles: [cpu]
|
|
restart: unless-stopped
|
|
ports:
|
|
- "127.0.0.1:8000:8000"
|
|
environment:
|
|
HF_TOKEN: ${HF_TOKEN:-}
|
|
volumes:
|
|
- gpu_cache:/root/.cache
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8000/docs"]
|
|
interval: 15s
|
|
timeout: 5s
|
|
retries: 10
|
|
start_period: 120s
|
|
networks:
|
|
default:
|
|
aliases:
|
|
- transcription
|
|
|
|
# ===========================================================
|
|
# Ollama — local LLM for summarization & topic detection
|
|
# Only started with --ollama-gpu or --ollama-cpu modes.
|
|
# ===========================================================
|
|
|
|
ollama:
|
|
image: ollama/ollama:latest
|
|
profiles: [ollama-gpu]
|
|
restart: unless-stopped
|
|
ports:
|
|
- "127.0.0.1:11435:11435"
|
|
volumes:
|
|
- ollama_data:/root/.ollama
|
|
environment:
|
|
OLLAMA_HOST: "0.0.0.0:11435"
|
|
OLLAMA_KEEP_ALIVE: "24h"
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: all
|
|
capabilities: [gpu]
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:11435/api/tags"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
ollama-cpu:
|
|
image: ollama/ollama:latest
|
|
profiles: [ollama-cpu]
|
|
restart: unless-stopped
|
|
ports:
|
|
- "127.0.0.1:11435:11435"
|
|
volumes:
|
|
- ollama_data:/root/.ollama
|
|
environment:
|
|
OLLAMA_HOST: "0.0.0.0:11435"
|
|
OLLAMA_KEEP_ALIVE: "24h" # keep model loaded to avoid reload delays
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:11435/api/tags"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
# ===========================================================
|
|
# Garage — local S3-compatible object storage (optional)
|
|
# ===========================================================
|
|
|
|
garage:
|
|
image: dxflrs/garage:v1.1.0
|
|
profiles: [garage]
|
|
restart: unless-stopped
|
|
ports:
|
|
- "3900:3900" # S3 API
|
|
- "3903:3903" # Admin API
|
|
volumes:
|
|
- garage_data:/var/lib/garage/data
|
|
- garage_meta:/var/lib/garage/meta
|
|
- ./data/garage.toml:/etc/garage.toml:ro
|
|
healthcheck:
|
|
test: ["CMD", "/garage", "stats"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 5s
|
|
|
|
# ===========================================================
|
|
# Caddy — reverse proxy with automatic SSL (optional)
|
|
# Maps 80:80 and 443:443 — only exposed ports in the stack.
|
|
# ===========================================================
|
|
|
|
caddy:
|
|
image: caddy:2-alpine
|
|
profiles: [caddy]
|
|
restart: unless-stopped
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
volumes:
|
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
- caddy_data:/data
|
|
- caddy_config:/config
|
|
depends_on:
|
|
- web
|
|
- server
|
|
|
|
# ===========================================================
|
|
# Hatchet + Daily.co workers (optional — for Daily.co multitrack processing)
|
|
# Auto-enabled when DAILY_API_KEY is configured in server/r
|
|
# ===========================================================
|
|
|
|
hatchet:
|
|
image: ghcr.io/hatchet-dev/hatchet/hatchet-lite:latest
|
|
profiles: [dailyco]
|
|
restart: on-failure
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
ports:
|
|
- "8888:8888"
|
|
- "7078:7077"
|
|
env_file:
|
|
- ./.env.hatchet
|
|
environment:
|
|
DATABASE_URL: "postgresql://reflector:reflector@postgres:5432/hatchet?sslmode=disable&connect_timeout=30"
|
|
SERVER_AUTH_COOKIE_INSECURE: "t"
|
|
SERVER_GRPC_BIND_ADDRESS: "0.0.0.0"
|
|
SERVER_GRPC_INSECURE: "t"
|
|
SERVER_GRPC_BROADCAST_ADDRESS: hatchet:7077
|
|
SERVER_GRPC_PORT: "7077"
|
|
SERVER_AUTH_SET_EMAIL_VERIFIED: "t"
|
|
SERVER_INTERNAL_CLIENT_INTERNAL_GRPC_BROADCAST_ADDRESS: hatchet:7077
|
|
volumes:
|
|
- hatchet_config:/config
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8888/api/live"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 30s
|
|
|
|
hatchet-worker-cpu:
|
|
build:
|
|
context: ./server
|
|
dockerfile: Dockerfile
|
|
image: monadicalsas/reflector-backend:latest
|
|
profiles: [dailyco]
|
|
restart: unless-stopped
|
|
env_file:
|
|
- ./server/.env
|
|
environment:
|
|
ENTRYPOINT: hatchet-worker-cpu
|
|
DATABASE_URL: postgresql+asyncpg://reflector:reflector@postgres:5432/reflector
|
|
REDIS_HOST: redis
|
|
CELERY_BROKER_URL: redis://redis:6379/1
|
|
CELERY_RESULT_BACKEND: redis://redis:6379/1
|
|
HATCHET_CLIENT_SERVER_URL: http://hatchet:8888
|
|
HATCHET_CLIENT_HOST_PORT: hatchet:7077
|
|
depends_on:
|
|
hatchet:
|
|
condition: service_healthy
|
|
volumes:
|
|
- server_data:/app/data
|
|
|
|
hatchet-worker-llm:
|
|
build:
|
|
context: ./server
|
|
dockerfile: Dockerfile
|
|
image: monadicalsas/reflector-backend:latest
|
|
profiles: [dailyco]
|
|
restart: unless-stopped
|
|
env_file:
|
|
- ./server/.env
|
|
environment:
|
|
ENTRYPOINT: hatchet-worker-llm
|
|
DATABASE_URL: postgresql+asyncpg://reflector:reflector@postgres:5432/reflector
|
|
REDIS_HOST: redis
|
|
CELERY_BROKER_URL: redis://redis:6379/1
|
|
CELERY_RESULT_BACKEND: redis://redis:6379/1
|
|
HATCHET_CLIENT_SERVER_URL: http://hatchet:8888
|
|
HATCHET_CLIENT_HOST_PORT: hatchet:7077
|
|
depends_on:
|
|
hatchet:
|
|
condition: service_healthy
|
|
volumes:
|
|
- server_data:/app/data
|
|
|
|
volumes:
|
|
postgres_data:
|
|
redis_data:
|
|
server_data:
|
|
gpu_cache:
|
|
garage_data:
|
|
garage_meta:
|
|
ollama_data:
|
|
caddy_data:
|
|
caddy_config:
|
|
hatchet_config:
|
|
|
|
networks:
|
|
default:
|
|
attachable: true
|