# BetterFrame stack: server + Angie proxy + Node-RED. # Kiosk runs on the Pi natively (not in Docker, needs Wayland/HDMI). # # Lives at repo root by convention — Docker Compose + Coolify both default # to looking here. All paths are repo-root-relative so they resolve # identically whether compose is invoked with or without --project-directory. # # Usage: # docker compose up -d --build # from repo root # # Volumes (override per-deployment via env — see Coolify "Environment"): # BF_DATA_VOLUME_NAME default "betterframe-data" # NODERED_DATA_VOLUME_NAME default "nodered-data" # BF_HOST_PORT default 80 (host edge port mapped to angie) # # Coolify ops: set these env vars on the resource so each deployment owns its # own named volumes (e.g. "bf-prod-data" vs "bf-staging-data"). For host bind # mounts or NFS / S3-CSI volumes, use Coolify's per-service "Storage" UI # rather than templating driver_opts here — JSON injection via env is brittle. # # Only ${BF_HOST_PORT}:80 is published on the host. Backend services and # Node-RED are reachable only from within the Docker network. version: "3.8" services: server: build: context: . dockerfile: deploy/docker/Dockerfile.server args: BF_SERVER_VERSION: ${BF_SERVER_VERSION:-} container_name: betterframe-server restart: unless-stopped # Env overrides win over sec-config.yaml — Coolify / k8s inject these. environment: - TZ=UTC - BF_DATA_DIR=/var/lib/betterframe - BF_SQLITE_PATH=/var/lib/betterframe/betterframe.db - BF_NODERED_URL=http://nodered:1880 - BF_SELF_URL=http://server:18080 - BF_SERVER_VERSION=${BF_SERVER_VERSION:-} - COOLIFY_GIT_COMMIT=${COOLIFY_GIT_COMMIT:-} - SOURCE_COMMIT=${SOURCE_COMMIT:-} # Optional: paste Ed25519 PEM private key here for firmware signing. # - BF_FIRMWARE_SIGNING_KEY= # Optional: single-purpose Bearer token for GitHub Actions firmware import. # Set GitHub's BF_AUTOIMPORT_API_KEY secret to the same value. # Generate with: openssl rand -base64 32 # - BF_FIRMWARE_IMPORT_API_KEY= # Optional MQTT telemetry bridge (ThingsBoard / HA / Influx / etc). # - BF_MQTT_URL=mqtt://broker:1883 # - BF_MQTT_USERNAME= # - BF_MQTT_PASSWORD= # - BF_MQTT_TOPIC_PREFIX=betterframe volumes: - betterframe-data:/var/lib/betterframe expose: - "18080" - "18081" - "18082" healthcheck: test: ["CMD-SHELL", "wget -qO- http://localhost:18080/healthz || exit 1"] interval: 30s timeout: 5s retries: 3 start_period: 30s networks: - betterframe angie: build: context: . dockerfile: deploy/docker/Dockerfile.angie container_name: betterframe-angie restart: unless-stopped depends_on: - server - nodered ports: - "${BF_HOST_PORT:-80}:80" networks: - betterframe nodered: build: context: . dockerfile: deploy/docker/Dockerfile.nodered container_name: betterframe-nodered restart: unless-stopped environment: - TZ=UTC volumes: - nodered-data:/data expose: - "1880" healthcheck: test: ["CMD-SHELL", "wget -q --spider http://localhost:1880/nrdp/ || exit 1"] interval: 30s timeout: 5s retries: 3 start_period: 90s networks: - betterframe volumes: # Top-level keys are the in-compose references used above. `name:` sets the # actual docker volume name on the host so multiple Coolify deployments on # the same host can share machine without name collisions. Default keeps # backward compat with existing single-host deployments. betterframe-data: name: ${BF_DATA_VOLUME_NAME:-betterframe-data} nodered-data: name: ${NODERED_DATA_VOLUME_NAME:-nodered-data} networks: betterframe: driver: bridge