name: "${COMPOSE_PROJECT_NAME:-announcements-v2}" services: web: build: context: . dockerfile: client/Dockerfile restart: unless-stopped init: true ports: - "${WEB_PORT:-5175}:80" depends_on: api: condition: service_healthy networks: app: # Only the web service is reachable from the shared reverse-proxy # network. Caddy resolves it as announcements-web:80; the API and object # storage stay private on the Announcements networks. tabernet: aliases: - announcements-web healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1/"] interval: 15s timeout: 5s retries: 3 start_period: 10s api: build: context: . dockerfile: server/Dockerfile restart: unless-stopped init: true environment: NODE_ENV: production HOST: 0.0.0.0 PORT: "7532" DATABASE_PATH: /data/db/announcements.sqlite APP_TIMEZONE: "${APP_TIMEZONE:-America/Chicago}" SHUTDOWN_TIMEOUT_MS: "${SHUTDOWN_TIMEOUT_MS:-10000}" DATABASE_BUSY_TIMEOUT_MS: "${DATABASE_BUSY_TIMEOUT_MS:-5000}" TRUST_PROXY: "${TRUST_PROXY:-true}" S3_ENDPOINT: http://seaweedfs:8333 S3_REGION: "${S3_REGION:-us-east-1}" S3_BUCKET: "${S3_BUCKET:-announcements-v2}" S3_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:?Set S3_ACCESS_KEY_ID in .env}" S3_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:?Set S3_SECRET_ACCESS_KEY in .env}" S3_FORCE_PATH_STYLE: "true" S3_CONNECT_TIMEOUT_MS: "${S3_CONNECT_TIMEOUT_MS:-2000}" S3_REQUEST_TIMEOUT_MS: "${S3_REQUEST_TIMEOUT_MS:-5000}" S3_MAX_ATTEMPTS: "${S3_MAX_ATTEMPTS:-2}" S3_HEALTH_PROBE_INTERVAL_MS: "${S3_HEALTH_PROBE_INTERVAL_MS:-30000}" UPLOAD_TEMP_DIRECTORY: /tmp/announcements-uploads UPLOAD_MAX_FILE_BYTES: "${UPLOAD_MAX_FILE_BYTES:-26214400}" UPLOAD_MAX_FILES: "${UPLOAD_MAX_FILES:-20}" IMAGE_MAX_INPUT_PIXELS: "${IMAGE_MAX_INPUT_PIXELS:-40000000}" MQTT_URL: "${MQTT_URL:-}" MQTT_USERNAME: "${MQTT_USERNAME:-}" MQTT_PASSWORD: "${MQTT_PASSWORD:-}" MQTT_TOPIC_PREFIX: "${MQTT_TOPIC_PREFIX:-announcements}" MQTT_RECONNECT_PERIOD_MS: "${MQTT_RECONNECT_PERIOD_MS:-5000}" MQTT_CONNECT_TIMEOUT_MS: "${MQTT_CONNECT_TIMEOUT_MS:-10000}" HA_WEBHOOK_URL: "${HA_WEBHOOK_URL:-}" HA_WEBHOOK_SECRET: "${HA_WEBHOOK_SECRET:-}" HA_WEBHOOK_TIMEOUT_MS: "${HA_WEBHOOK_TIMEOUT_MS:-10000}" DISPLAY_OFFLINE_THRESHOLD_MS: "${DISPLAY_OFFLINE_THRESHOLD_MS:-45000}" volumes: - app-data:/data depends_on: seaweedfs: condition: service_started networks: - app - storage healthcheck: test: - CMD - node - -e - "fetch('http://127.0.0.1:7532/health/ready').then((response) => process.exit(response.ok ? 0 : 1)).catch(() => process.exit(1))" interval: 15s timeout: 5s retries: 5 start_period: 15s stop_grace_period: 15s seaweedfs: image: chrislusf/seaweedfs:4.39 restart: unless-stopped command: ["mini", "-dir=/data", "-ip=seaweedfs"] environment: AWS_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:?Set S3_ACCESS_KEY_ID in .env}" AWS_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:?Set S3_SECRET_ACCESS_KEY in .env}" S3_BUCKET: "${S3_BUCKET:-announcements-v2}" volumes: - seaweedfs-data:/data expose: - "8333" networks: - storage healthcheck: test: - CMD-SHELL - >- wget -q -O /dev/null http://127.0.0.1:9333/readyz && wget -q -O /dev/null http://127.0.0.1:8333/readyz interval: 15s timeout: 5s retries: 5 start_period: 20s stop_grace_period: 30s networks: app: storage: internal: true tabernet: external: true volumes: app-data: seaweedfs-data: