services: minuspod: image: ttlequals0/minuspod:${MINUSPOD_VERSION:-latest} platform: linux/amd64 # The container ships a non-root `minuspod` user at UID/GID 1000 # (entrypoint.sh drops root via setpriv after fixing volume ownership). # Override here to pin a specific APP_UID/APP_GID if your volume is # owned by a different user -- e.g. `user: "2000:2000"`. Leave unset # to use the image default (1000:1000). # user: "1000:1000" ports: - "${MINUSPOD_PORT:-8000}:${MINUSPOD_PORT:-8000}" volumes: - ./data:/app/data # Optional: Custom assets directory for replacement audio # Place your own replace.mp3 file here to customize the sound played where ads were removed # If not mounted, the built-in default audio marker is used # - ./assets:/app/assets:ro environment: # ================================================================= # LLM Provider Configuration (set in .env file) # ================================================================= # LLM_PROVIDER: anthropic (default), openrouter, openai-compatible, ollama # See .env.example for full configuration options per provider - LLM_PROVIDER=${LLM_PROVIDER:-anthropic} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - OPENROUTER_API_KEY=${OPENROUTER_API_KEY} - OPENAI_BASE_URL=${OPENAI_BASE_URL} - OPENAI_API_KEY=${OPENAI_API_KEY} - OPENAI_MODEL=${OPENAI_MODEL} # ================================================================= # Whisper Configuration # ================================================================= # Option 1: Local Whisper (default, GPU required) - WHISPER_MODEL=${WHISPER_MODEL:-small} - WHISPER_DEVICE=${WHISPER_DEVICE:-cuda} # Option 2: External OpenAI-compatible Whisper API (Groq, OpenAI, whisper.cpp) # - WHISPER_BACKEND=openai-api # - WHISPER_API_BASE_URL=https://api.groq.com/openai/v1 # - WHISPER_API_KEY=${WHISPER_API_KEY} # - WHISPER_API_MODEL=whisper-large-v3-turbo # ================================================================= # Server Configuration # ================================================================= - BASE_URL=${BASE_URL:-http://localhost:8000} # Internal listen port. Default 8000. Useful for host networking or # running multiple instances. Ignored when GUNICORN_BIND is set. - MINUSPOD_PORT=${MINUSPOD_PORT:-8000} # ================================================================= # 2.0.0+ Security (defaults shown; override via .env when needed) # ================================================================= # Encrypts provider API keys + scheduled DB backups at rest. # Strongly recommended in any non-throwaway deployment. # - MINUSPOD_MASTER_PASSPHRASE=${MINUSPOD_MASTER_PASSPHRASE} # SESSION_COOKIE_SECURE defaults to true in 2.0.0+. Set to false # only if serving over plain HTTP. # - SESSION_COOKIE_SECURE=${SESSION_COOKIE_SECURE:-true} # Set once the deployment is HTTPS-only. HSTS traps browsers so # do not flip this on a dual-protocol setup. # - MINUSPOD_ENABLE_HSTS=${MINUSPOD_ENABLE_HSTS:-false} # Opt-in error reporting. URL or DSN from sentry.io. # - SENTRY_DSN=${SENTRY_DSN} # ================================================================= # Reverse proxy / tunnel (behind Cloudflare, nginx, Traefik, ...) # ================================================================= # Number of trusted proxy hops in front of this container. # 0 (default) = no proxy; the container sees the real client IP. # 1 = one proxy (Cloudflare tunnel, nginx, Traefik, cloudflared). # Set to 1 when the `tunnel` profile is active, or any time the # container sits behind a reverse proxy, or login lockout and # per-IP rate limits silently never fire. See README "Client IP # for login lockout" for the full impact. - MINUSPOD_TRUSTED_PROXY_COUNT=${MINUSPOD_TRUSTED_PROXY_COUNT:-0} # ================================================================= # Deprecated -- Retention is managed via Settings > Storage in # the UI. This env var still works for backward compat. # ================================================================= # - RETENTION_PERIOD=${RETENTION_PERIOD:-1440} healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:$${MINUSPOD_PORT:-8000}/api/v1/health || exit 1"] interval: 30s timeout: 5s retries: 3 start_period: 30s deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] logging: driver: json-file options: max-size: "50m" max-file: "3" restart: unless-stopped expose: - "${MINUSPOD_PORT:-8000}" security_opt: - "no-new-privileges:true" cap_drop: - ALL cap_add: # The entrypoint chowns the data volume and drops root via setpriv, which # needs these caps; under a bare cap_drop: ALL it crash-loops. Omit this # block if you set `user:` above (the entrypoint then needs no caps). - SETUID - SETGID - CHOWN - DAC_OVERRIDE - FOWNER # Uncomment if using the wrapper service # depends_on: # - claude-wrapper # ================================================================= # Claude Code OpenAI Wrapper (Optional) # ================================================================= # Uses your Claude Max subscription instead of API credits # Enable with: docker compose --profile wrapper up -d # # First time setup: # 1. docker compose --profile wrapper run --rm claude-wrapper claude auth login # 2. Follow the OAuth prompts to authenticate # 3. docker compose --profile wrapper up -d # # Or use API key directly by setting ANTHROPIC_API_KEY in the wrapper claude-wrapper: image: ghcr.io/richardatct/claude-code-openai-wrapper:latest ports: - "8001:8000" # Expose on different port to avoid conflict environment: # Option A: Use API key (simpler, uses API credits) # - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} # Option B: Use OAuth (uses Max subscription) # Leave ANTHROPIC_API_KEY unset and use `claude auth login` # Optional: Protect the wrapper endpoint with an API key # - ENABLE_API_KEY_PROTECTION=true volumes: # Persist Claude CLI authentication - claude-auth:/root/.claude logging: driver: json-file options: max-size: "50m" max-file: "3" restart: unless-stopped profiles: - wrapper tunnel: image: cloudflare/cloudflared command: tunnel run environment: - TUNNEL_TOKEN=${TUNNEL_TOKEN} depends_on: - minuspod logging: driver: json-file options: max-size: "50m" max-file: "3" restart: unless-stopped profiles: - tunnel volumes: claude-auth: