networks: infoscreen-net: driver: bridge services: proxy: image: nginx:1.25 container_name: infoscreen-proxy restart: unless-stopped ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./certs:/etc/nginx/certs:ro # Mount host media folder into nginx so it can serve uploaded media - ./server/media/:/opt/infoscreen/server/media/:ro depends_on: - server - dashboard networks: - infoscreen-net db: image: mariadb:11.2 container_name: infoscreen-db restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} MYSQL_DATABASE: ${DB_NAME} MYSQL_USER: ${DB_USER} MYSQL_PASSWORD: ${DB_PASSWORD} volumes: - db-data:/var/lib/mysql networks: - infoscreen-net healthcheck: test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] interval: 30s timeout: 5s retries: 3 start_period: 30s mqtt: image: eclipse-mosquitto:2.0.21 container_name: infoscreen-mqtt restart: unless-stopped command: > sh -c 'set -eu; : "$${MQTT_USER:?MQTT_USER not set}"; : "$${MQTT_PASSWORD:?MQTT_PASSWORD not set}"; touch /mosquitto/config/passwd; chmod 600 /mosquitto/config/passwd; mosquitto_passwd -b /mosquitto/config/passwd "$${MQTT_USER}" "$${MQTT_PASSWORD}"; if [ -n "$${MQTT_CANARY_USER:-}" ] && [ -n "$${MQTT_CANARY_PASSWORD:-}" ]; then mosquitto_passwd -b /mosquitto/config/passwd "$${MQTT_CANARY_USER}" "$${MQTT_CANARY_PASSWORD}"; fi; exec mosquitto -c /mosquitto/config/mosquitto.conf' volumes: - ./mosquitto/config:/mosquitto/config - ./mosquitto/data:/mosquitto/data - ./mosquitto/log:/mosquitto/log ports: - "1883:1883" - "9001:9001" environment: - MQTT_USER=${MQTT_USER} - MQTT_PASSWORD=${MQTT_PASSWORD} - MQTT_CANARY_USER=${MQTT_CANARY_USER:-} - MQTT_CANARY_PASSWORD=${MQTT_CANARY_PASSWORD:-} networks: - infoscreen-net healthcheck: test: [ "CMD-SHELL", "mosquitto_pub -h localhost -u $$MQTT_USER -P $$MQTT_PASSWORD -t test -m 'health' || exit 1", ] interval: 30s timeout: 5s retries: 3 start_period: 10s # Verwende fertige Images statt Build server: image: ghcr.io/robbstarkaustria/infoscreen-api:latest container_name: infoscreen-api restart: unless-stopped depends_on: db: condition: service_healthy mqtt: condition: service_healthy environment: DB_CONN: "mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}" DB_USER: ${DB_USER} DB_PASSWORD: ${DB_PASSWORD} DB_NAME: ${DB_NAME} DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} DB_HOST: db FLASK_ENV: production FLASK_SECRET_KEY: ${FLASK_SECRET_KEY} MQTT_BROKER_URL: mqtt://mqtt:1883 MQTT_USER: ${MQTT_USER} MQTT_PASSWORD: ${MQTT_PASSWORD} DEFAULT_SUPERADMIN_USERNAME: ${DEFAULT_SUPERADMIN_USERNAME:-superadmin} DEFAULT_SUPERADMIN_PASSWORD: ${DEFAULT_SUPERADMIN_PASSWORD} networks: - infoscreen-net healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 5s retries: 3 start_period: 40s command: > bash -c "alembic -c /app/server/alembic.ini upgrade head && python /app/server/init_defaults.py && python /app/server/init_academic_periods.py && exec gunicorn server.wsgi:app --bind 0.0.0.0:8000" dashboard: image: ghcr.io/robbstarkaustria/infoscreen-dashboard:latest # Oder wo auch immer Ihre Images liegen container_name: infoscreen-dashboard restart: unless-stopped depends_on: server: condition: service_healthy environment: NODE_ENV: production VITE_API_URL: ${API_URL} networks: - infoscreen-net listener: image: ghcr.io/robbstarkaustria/infoscreen-listener:latest # Oder wo auch immer Ihre Images liegen container_name: infoscreen-listener restart: unless-stopped depends_on: db: condition: service_healthy mqtt: condition: service_healthy environment: DB_CONN: "mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}" DB_USER: ${DB_USER} DB_PASSWORD: ${DB_PASSWORD} DB_NAME: ${DB_NAME} DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} API_BASE_URL: http://server:8000 MQTT_BROKER_HOST: ${MQTT_BROKER_HOST:-mqtt} MQTT_BROKER_PORT: ${MQTT_BROKER_PORT:-1883} MQTT_USER: ${MQTT_USER} MQTT_PASSWORD: ${MQTT_PASSWORD} networks: - infoscreen-net scheduler: image: ghcr.io/robbstarkaustria/infoscreen-scheduler:latest container_name: infoscreen-scheduler restart: unless-stopped depends_on: # HINZUGEFÜGT: Stellt sicher, dass die DB vor dem Scheduler startet db: condition: service_healthy mqtt: condition: service_healthy environment: # HINZUGEFÜGT: Datenbank-Verbindungsstring DB_CONN: "mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}" MQTT_BROKER_HOST: ${MQTT_BROKER_HOST:-mqtt} MQTT_BROKER_PORT: ${MQTT_BROKER_PORT:-1883} MQTT_USER: ${MQTT_USER} MQTT_PASSWORD: ${MQTT_PASSWORD} POLL_INTERVAL_SECONDS: ${POLL_INTERVAL_SECONDS:-30} POWER_INTENT_PUBLISH_ENABLED: ${POWER_INTENT_PUBLISH_ENABLED:-false} POWER_INTENT_HEARTBEAT_ENABLED: ${POWER_INTENT_HEARTBEAT_ENABLED:-true} POWER_INTENT_EXPIRY_MULTIPLIER: ${POWER_INTENT_EXPIRY_MULTIPLIER:-3} POWER_INTENT_MIN_EXPIRY_SECONDS: ${POWER_INTENT_MIN_EXPIRY_SECONDS:-90} CRASH_RECOVERY_ENABLED: ${CRASH_RECOVERY_ENABLED:-false} CRASH_RECOVERY_GRACE_SECONDS: ${CRASH_RECOVERY_GRACE_SECONDS:-180} CRASH_RECOVERY_LOCKOUT_MINUTES: ${CRASH_RECOVERY_LOCKOUT_MINUTES:-15} networks: - infoscreen-net volumes: db-data: