Ctrl K
ComunidadGuías…

compose.yaml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
name: mediahub

x-logging: &logging
  driver: json-file
  options:
    max-size: "10m"
    max-file: "5"

x-backend-env: &backend-env
  MEDIAHUB_DATABASE_URL: postgresql+psycopg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
  MEDIAHUB_STORAGE_ROOT: /data/storage
  MEDIAHUB_ENVIRONMENT: ${MEDIAHUB_ENVIRONMENT:-production}
  MEDIAHUB_TIMEZONE: ${MEDIAHUB_TIMEZONE:-Asia/Taipei}
  MEDIAHUB_MAX_UPLOAD_BYTES: ${MEDIAHUB_MAX_UPLOAD_BYTES:-21474836480}
  MEDIAHUB_MIN_FREE_BYTES: ${MEDIAHUB_MIN_FREE_BYTES:-2147483648}
  MEDIAHUB_FFMPEG_THREADS: ${MEDIAHUB_FFMPEG_THREADS:-4}
  MEDIAHUB_MASTER_KEY: ${MEDIAHUB_MASTER_KEY:?run scripts/init-env.sh (MEDIAHUB_MASTER_KEY missing)}
  MEDIAHUB_ALLOW_SIMULATED_NODES: ${MEDIAHUB_ALLOW_SIMULATED_NODES:-false}
  MEDIAHUB_PUBLIC_URL: ${MEDIAHUB_PUBLIC_URL:-}
  MEDIAHUB_NODE_OFFLINE_AFTER_SECONDS: ${MEDIAHUB_NODE_OFFLINE_AFTER_SECONDS:-90}
  MEDIAHUB_NODE_HEARTBEAT_SECONDS: ${MEDIAHUB_NODE_HEARTBEAT_SECONDS:-30}
  TZ: ${MEDIAHUB_TIMEZONE:-Asia/Taipei}

services:
  db:
    image: postgres:17-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 20
    logging: *logging

  api:
    build:
      context: ./backend
      target: base
    image: mediahub-api:${HUB_IMAGE_TAG:-latest}
    restart: unless-stopped
    environment: *backend-env
    volumes:
      - storage:/data/storage
      # Public root CA certificate only (exported by the caddy container) — lets pairing
      # payloads carry the CA fingerprint for pinning. Caddy's private keys stay in caddy_data.
      - ca_public:/ca-public:ro
      # Android storage-node app, built on the host (scripts/build-android.sh), served to admins.
      - ./android/dist:/app/android-dist:ro
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/health', timeout=4)"]
      interval: 10s
      timeout: 5s
      retries: 12
      start_period: 20s
    mem_limit: 1g
    logging: *logging

  worker:
    image: mediahub-api:${HUB_IMAGE_TAG:-latest}
    restart: unless-stopped
    command: ["python", "-m", "app.worker"]
    environment: *backend-env
    volumes:
      - storage:/data/storage
    depends_on:
      api:
        condition: service_healthy
    # Transcoding is CPU-heavy: cap it so the rest of the machine stays responsive.
    cpus: ${MEDIAHUB_WORKER_CPUS:-4}
    mem_limit: 3g
    stop_grace_period: 40s
    logging: *logging

  caddy:
    build:
      context: .
      dockerfile: deploy/caddy/Dockerfile
    image: mediahub-web:${HUB_IMAGE_TAG:-latest}
    restart: unless-stopped
    environment:
      HUB_SITES: ${HUB_SITES:-https://localhost}
      HUB_DEFAULT_SNI: ${HUB_DEFAULT_SNI:-localhost}
      HUB_MAX_UPLOAD: ${HUB_MAX_UPLOAD:-20GB}
    ports:
      # Docker-published ports bypass ufw. Default binds to loopback only; set
      # HUB_BIND to this machine's LAN IP to serve phones/PCs on the same network.
      - "${HUB_BIND:-127.0.0.1}:${HUB_HTTPS_PORT:-443}:443"
    volumes:
      - caddy_data:/data
      - caddy_config:/config
      - ca_public:/ca-public
    depends_on:
      api:
        condition: service_healthy
    logging: *logging

  # `docker compose --profile test run --rm tests` — isolated DB + temp storage.
  tests:
    profiles: ["test"]
    build:
      context: ./backend
      target: test
    image: mediahub-api:test
    environment:
      MEDIAHUB_DATABASE_URL: postgresql+psycopg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/mediahub_test
      MEDIAHUB_STORAGE_ROOT: /tmp/mediahub-test
      MEDIAHUB_ENVIRONMENT: test
      MEDIAHUB_COOKIE_SECURE: "false"
      MEDIAHUB_ALLOW_SIMULATED_NODES: "true"
    depends_on:
      db:
        condition: service_healthy

volumes:
  pgdata:
  storage:
  caddy_data:
  caddy_config:
  ca_public: