# Family Home Lab — core stack + tool containers # Deploy on .13: cd /home/sam/Docker/Containers/family-home-lab && docker compose up -d # Tool containers (photo/video/audio) are behind profile "tools": # docker compose --profile tools up -d # (Their images need verification per plan.md §4 — see each tool's README.) name: family-home-lab x-fhl-logging: &logging logging: driver: json-file options: max-size: "10m" max-file: "3" services: # ----- Core stack ----- postgres: image: pgvector/pgvector:pg16 restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} volumes: - pgdata:/var/lib/postgresql/data networks: [fhl-net] <<: *logging # No host port published: reachable only inside fhl-net. .13 already runs its # own postgres on 5432/5433/5434; we avoid the conflict entirely. redis: image: redis:7-alpine restart: unless-stopped command: redis-server --appendonly yes volumes: - redisdata:/data networks: [fhl-net] <<: *logging rabbitmq: image: rabbitmq:3-management-alpine restart: unless-stopped environment: RABBITMQ_DEFAULT_USER: guest RABBITMQ_DEFAULT_PASS: guest RABBITMQ_DEFAULT_VHOST: / volumes: - rabbitmqdata:/var/lib/rabbitmq networks: [fhl-net] <<: *logging garage: image: dxflrs/garage:v1.0.1 restart: unless-stopped volumes: - ./garage/garage.toml:/etc/garage.toml:ro - /mnt/data/family-home-lab/garage-data:/var/lib/garage/data - /mnt/data/family-home-lab/garage-meta:/var/lib/garage/meta ports: - "3900:3900" # S3 API - "3902:3902" # admin / web environment: GARAGE_RPC_SECRET: ${GARAGE_RPC_SECRET} GARAGE_ADMIN_TOKEN: ${GARAGE_ADMIN_TOKEN} GARAGE_METRICS_TOKEN: ${GARAGE_METRICS_TOKEN} networks: [fhl-net] <<: *logging portal: build: context: . dockerfile: portal/Dockerfile restart: unless-stopped ports: - "8500:8500" environment: DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB} CELERY_BROKER_URL: amqp://guest:guest@rabbitmq:5672// REDIS_URL: redis://redis:6379/0 S3_ENDPOINT_URL: http://garage:3900 S3_REGION: ${S3_REGION} S3_ACCESS_KEY: ${S3_ACCESS_KEY} S3_SECRET_KEY: ${S3_SECRET_KEY} SESSION_SECRET: ${SESSION_SECRET} ADMIN_USERNAME: ${ADMIN_USERNAME} ADMIN_PASSWORD: ${ADMIN_PASSWORD} ADMIN_FULLNAME: ${ADMIN_FULLNAME} PI_DASHBOARD_DIR: /pi-dashboard volumes: - /mnt/data/family-home-lab/pi-dashboard:/pi-dashboard:ro depends_on: - postgres - redis - rabbitmq - garage networks: [fhl-net] <<: *logging worker: build: context: . dockerfile: portal/Dockerfile restart: unless-stopped command: celery -A portal.tasks.celery_app worker --loglevel=info environment: DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB} CELERY_BROKER_URL: amqp://guest:guest@rabbitmq:5672// REDIS_URL: redis://redis:6379/0 S3_ENDPOINT_URL: http://garage:3900 S3_REGION: ${S3_REGION} S3_ACCESS_KEY: ${S3_ACCESS_KEY} S3_SECRET_KEY: ${S3_SECRET_KEY} SESSION_SECRET: ${SESSION_SECRET} depends_on: - postgres - redis - rabbitmq - garage networks: [fhl-net] <<: *logging transcriber: build: context: . dockerfile: transcriber/Dockerfile restart: unless-stopped command: celery -A portal.tasks.celery_app worker -Q transcription --concurrency=1 --loglevel=info environment: DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB} CELERY_BROKER_URL: amqp://guest:guest@rabbitmq:5672// REDIS_URL: redis://redis:6379/0 S3_ENDPOINT_URL: http://garage:3900 S3_REGION: ${S3_REGION} S3_ACCESS_KEY: ${S3_ACCESS_KEY} S3_SECRET_KEY: ${S3_SECRET_KEY} SESSION_SECRET: ${SESSION_SECRET} depends_on: - postgres - redis - rabbitmq - garage networks: [fhl-net] <<: *logging transcriber-mus: build: context: . dockerfile: transcriber-mus/Dockerfile restart: unless-stopped command: celery -A portal.tasks.celery_app worker -Q transcription-mus --concurrency=1 --loglevel=info environment: DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB} CELERY_BROKER_URL: amqp://guest:guest@rabbitmq:5672// REDIS_URL: redis://redis:6379/0 S3_ENDPOINT_URL: http://garage:3900 S3_REGION: ${S3_REGION} S3_ACCESS_KEY: ${S3_ACCESS_KEY} S3_SECRET_KEY: ${S3_SECRET_KEY} SESSION_SECRET: ${SESSION_SECRET} HUGGINGFACE_TOKEN: ${HUGGINGFACE_TOKEN:-} HF_TOKEN: ${HUGGINGFACE_TOKEN:-} # huggingface_hub/transformers read this depends_on: - postgres - redis - rabbitmq - garage networks: [fhl-net] <<: *logging # ----- Tool containers (profile "tools") ----- # Images per Obsidian blueprint: media tools via LinuxServer standalone apps. # Host ports reassigned (8081 taken by airflow, 3000 taken by a NixOS # service) -> video 8083, audio 8084, gimp 8087. gimp: image: ${IMAGE_GIMP:-lscr.io/linuxserver/gimp:latest} profiles: ["tools"] restart: unless-stopped environment: PUID: 1000 PGID: 100 TZ: Australia/Melbourne DARK_MODE: "true" ports: - "8087:3000" volumes: - gimp-config:/config - /mnt/data/family-home-lab/shared-media:/media:ro - /home/sam:/home/sam:ro - /home/sam/Downloads:/home/abc/Downloads - /home/sam/Pictures:/home/abc/Pictures networks: [fhl-net] shm_size: 1gb <<: *logging video-editor: image: ${IMAGE_VIDEO:-lscr.io/linuxserver/kdenlive:latest} profiles: ["tools"] restart: unless-stopped environment: PUID: 1000 PGID: 100 TZ: Australia/Perth ports: - "8083:3000" volumes: - video-config:/config - /mnt/data/family-home-lab/shared-media:/media:ro networks: [fhl-net] <<: *logging audio-editor: image: ${IMAGE_AUDIO:-lscr.io/linuxserver/audacity:latest} profiles: ["tools"] restart: unless-stopped environment: PUID: 1000 PGID: 100 TZ: Australia/Perth ports: - "8084:3000" volumes: - audio-config:/config - /mnt/data/family-home-lab/shared-media:/media:ro networks: [fhl-net] <<: *logging volumes: pgdata: redisdata: rabbitmqdata: gimp-config: video-config: audio-config: networks: fhl-net: driver: bridge