# Standalone Compose file for the Pi. # # If you already run Caddy and PostgreSQL from another Compose project, either # merge the `schulcloud-mcp` service below into that project's file, or keep # this file separate and attach it to the existing Caddy network — see the # `networks` block at the bottom and deploy/Caddyfile.snippet. services: # Dev/standalone Postgres. On the Pi, point DATABASE_URL at the existing # instance instead and remove this service — the schema lives in its own # database and user, so it coexists with whatever else is already there. postgres: image: postgres:17-alpine container_name: schulcloud-mcp-db restart: unless-stopped environment: POSTGRES_DB: schulcloud POSTGRES_USER: schulcloud POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-schulcloud} volumes: - pgdata:/var/lib/postgresql/data networks: - caddy healthcheck: test: ["CMD-SHELL", "pg_isready -U schulcloud -d schulcloud"] interval: 10s timeout: 5s retries: 5 schulcloud-mcp: build: . image: schulcloud-mcp:latest container_name: schulcloud-mcp restart: unless-stopped env_file: .env environment: PORT: 8080 BIND_HOST: 0.0.0.0 MIRROR_DIR: /data/mirror STATE_DIR: /data/state depends_on: postgres: condition: service_healthy volumes: # The mirror and a replaced Schulcloud token are the only things this # server writes; everything else stays read-only, so each gets its own # volume rather than loosening read_only. - mirror:/data/mirror - state:/data/state # No ports are published to the host: Caddy reaches the container over the # shared Docker network, so the only way in from the internet is through # Caddy's TLS and this server's bearer check. expose: - "8080" networks: - caddy logging: driver: json-file options: max-size: "10m" max-file: "3" security_opt: - no-new-privileges:true read_only: true tmpfs: - /tmp cap_drop: - ALL volumes: pgdata: mirror: state: networks: caddy: # Set to true once this joins the network your existing Caddy already uses, # and change the name to match (`docker network ls` to find it). external: false name: caddy