# BizGaze Support — deployed behind the existing Nginx Proxy Manager. # No host ports are published: NPM reaches this container by name on the # shared `nginx_proxy_manager_default` network. TLS is terminated by NPM, # which proxies https://remote.bizgaze.com -> bizgaze-support:8090. services: app: build: . image: bizgaze-support:latest container_name: bizgaze-support restart: unless-stopped environment: - PORT=8090 - DB_PATH=/data/data.db # Desktop installers + auto-update feed live on the persistent volume so uploaded # builds survive image rebuilds (a plain image path would be wiped on every deploy). - DOWNLOADS_DIR=/data/downloads # Chat uploads / recordings / transcripts on the persistent volume too, so they survive image # rebuilds (otherwise old shared images 404 as "broken image" after every deploy). - UPLOADS_DIR=/data/uploads # Max chat-attachment size in MB (default 1024 = 1 GB). The app streams uploads to /data/uploads, so # large files don't buffer in memory. IMPORTANT: also set Nginx Proxy Manager's client_max_body_size # for remote.bizgaze.com to at least this (Advanced tab: `client_max_body_size 1024m;`) or the proxy # rejects big uploads before they reach the app. - MAX_UPLOAD_MB=1024 - REC_DIR=/data/recordings - TRANS_DIR=/data/transcripts # Secrets (TURN credentials, SSO_SECRET, BIZGAZE_WEBHOOK_URL, etc.) live in # a .env file next to this compose file. It is gitignored — never committed. # See .env.example for the expected keys. env_file: - path: .env required: false volumes: - bizgaze_support_data:/data # persists data.db across rebuilds networks: - npm # Wait for Postgres to be healthy before starting. Only matters when DB_BACKEND=pg (else the app uses # the local SQLite file and ignores pg), but it's harmless on SQLite — pg comes up in a second or two. depends_on: bizgazepg: condition: service_healthy # PostgreSQL — the app's data store when DB_BACKEND=pg (default is the local SQLite file). Distinct # service/container name so it never collides with the other postgres containers on the shared NPM # network; the app reaches it as `bizgaze-postgres`. Data on its own named volume. bizgazepg: image: postgres:16 container_name: bizgaze-postgres restart: unless-stopped environment: - POSTGRES_USER=bizgaze - POSTGRES_DB=bizgaze # Password comes from the same .env as the app (compose interpolates ${...} from the .env in this dir). # NOTE: Postgres only applies POSTGRES_PASSWORD on FIRST init of an empty data volume. - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-bizgaze_local} volumes: - bizgaze_pg_data:/var/lib/postgresql/data networks: - npm healthcheck: test: ["CMD-SHELL", "pg_isready -U bizgaze -d bizgaze"] interval: 5s timeout: 3s retries: 12 # Redis — cross-instance real-time fan-out (chat/presence), used only when PUBSUB_BACKEND=redis. Dormant # by default (behind the 'scale' profile, like livekit), so a normal deploy never starts it and the app # stays single-instance on the in-memory pubsub. To run multiple app instances: start this # (`docker compose --profile scale up -d`), set PUBSUB_BACKEND=redis + REDIS_URL in .env, and put the app # behind a load balancer with sticky sessions for the /ws WebSocket. (Meeting SIGNALING state is still # per-process — cross-instance meetings need sticky routing or further work; chat/presence fan out here.) bizgazeredis: image: redis:7-alpine container_name: bizgaze-redis restart: unless-stopped profiles: ["scale"] networks: - npm # LiveKit SFU — meeting media server. Optional: only started/used when the app's .env has # LIVEKIT_URL/API_KEY/API_SECRET set (otherwise meetings use the built-in P2P mesh). NPM proxies # wss://livekit.bizgaze.com -> livekit:7880 (signaling); media flows over the published UDP/TCP # ports below, NOT through NPM. Single-node (no Redis) — consistent with the app's single-instance rule. livekit: # v1.8+ implements the /rtc/v1 signaling path (protocol 17) that the bundled # livekit-client@2.20 uses. On the older v1.7 the client fell back to the legacy path and # track publishing broke (mic/cam wouldn't turn on). Keep this within one minor of the client. image: livekit/livekit-server:v1.9 container_name: bizgaze-livekit restart: unless-stopped # Dormant by default: a normal `docker compose up -d` / deploy.sh does NOT start it. Enable SFU # explicitly with `docker compose --profile sfu up -d` after setting the LIVEKIT_* vars (see DEPLOY.md). profiles: ["sfu"] command: --config /etc/livekit.yaml environment: # key: secret, sourced from the same .env as the app so both sign/verify with the same secret. - "LIVEKIT_KEYS=${LIVEKIT_API_KEY}: ${LIVEKIT_API_SECRET}" volumes: - ./livekit.yaml:/etc/livekit.yaml:ro ports: - "7881:7881" # WebRTC over TCP (fallback) - "50000:50000/udp" # single WebRTC media UDP port (must match livekit.yaml rtc.udp_port) networks: - npm networks: npm: external: true name: nginx_proxy_manager_default volumes: bizgaze_support_data: bizgaze_pg_data: