# Docker Compose for Coolify deployment of ECHODO. # # Usage in Coolify: # - New Resource → Docker Compose → connect this repo # - Build pack: Docker Compose # - Compose file path: docker/docker-compose.coolify.yml # - Set domains in Coolify on the `web` and `collab` services using http:// # (CT 100 Traefik handles TLS termination per AGENT-DEPLOY.md) # # Path conventions: # Coolify invokes `docker compose` with --project-directory set to the # repository root, NOT this file's directory. So all build contexts and # dockerfile paths below are written relative to the repo root. # # Differences vs. docker/docker-compose.yml: # - No bundled postgres / redis (uses shared CT 102 services) # - No host port mappings (Coolify's Traefik routes by container labels) # - Uses Coolify SERVICE_FQDN_* magic env vars so Coolify auto-wires Traefik labels services: web: build: context: . dockerfile: docker/Dockerfile.web restart: unless-stopped environment: # Coolify FQDN magic var — set the domain in the Coolify UI for this service. # SERVICE_FQDN_WEB_3000 makes Coolify expose the container on port 3000 via Traefik. - SERVICE_FQDN_WEB_3000 - DATABASE_URL=${DATABASE_URL} - REDIS_URL=${REDIS_URL} - NEXTAUTH_URL=${NEXTAUTH_URL} - NEXTAUTH_SECRET=${NEXTAUTH_SECRET} - AUTH_SECRET=${AUTH_SECRET} - AUTH_DEV_PASSWORD=${AUTH_DEV_PASSWORD} - AUTH_GITHUB_ID=${AUTH_GITHUB_ID} - AUTH_GITHUB_SECRET=${AUTH_GITHUB_SECRET} - AUTH_GOOGLE_ID=${AUTH_GOOGLE_ID} - AUTH_GOOGLE_SECRET=${AUTH_GOOGLE_SECRET} - AUTH_AUTHENTIK_ID=${AUTH_AUTHENTIK_ID} - AUTH_AUTHENTIK_SECRET=${AUTH_AUTHENTIK_SECRET} - AUTH_AUTHENTIK_ISSUER=${AUTH_AUTHENTIK_ISSUER} - COLLAB_SERVER_URL=${COLLAB_SERVER_URL} - NEXT_PUBLIC_COLLAB_SERVER_URL=${NEXT_PUBLIC_COLLAB_SERVER_URL} - NEXT_PUBLIC_UMAMI_SCRIPT=${NEXT_PUBLIC_UMAMI_SCRIPT} - NEXT_PUBLIC_UMAMI_WEBSITE_ID=${NEXT_PUBLIC_UMAMI_WEBSITE_ID} - NEXT_PUBLIC_LIBREDESK_URL=${NEXT_PUBLIC_LIBREDESK_URL} - NEXT_PUBLIC_LIBREDESK_WIDGET_ID=${NEXT_PUBLIC_LIBREDESK_WIDGET_ID} - NEXT_PUBLIC_DIRECTUS_URL=${NEXT_PUBLIC_DIRECTUS_URL} - DIRECTUS_FEEDBACK_TOKEN=${DIRECTUS_FEEDBACK_TOKEN} - OPENAI_API_KEY=${OPENAI_API_KEY} - OPENAI_BASE_URL=${OPENAI_BASE_URL} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - NODE_ENV=production - NEXT_TELEMETRY_DISABLED=1 expose: - "3000" healthcheck: test: - CMD-SHELL - "wget -qO- --timeout=3 http://127.0.0.1:3000/ >/dev/null || exit 1" interval: 30s timeout: 5s retries: 3 start_period: 90s networks: - echodo collab: build: context: . dockerfile: docker/Dockerfile.collab restart: unless-stopped environment: # Separate FQDN for the websocket service, e.g. collab.echodo.stillwell.cloud - SERVICE_FQDN_COLLAB_1234 - DATABASE_URL=${DATABASE_URL} - REDIS_URL=${REDIS_URL} - PORT=1234 - NODE_ENV=production expose: - "1234" healthcheck: test: - CMD-SHELL - 'node -e "const p=+(process.env.PORT||1234);require(''net'').createConnection(p,''127.0.0.1'').on(''connect'',()=>process.exit(0)).on(''error'',()=>process.exit(1))"' interval: 30s timeout: 5s retries: 3 start_period: 25s networks: - echodo # MCP server is stdio-based today; deploy only if you want it reachable on the LAN # for future HTTP/SSE transport. Comment the whole block out if not needed. mcp: build: context: . dockerfile: docker/Dockerfile.mcp args: MCP_SERVER_PORT: ${MCP_SERVER_PORT:-3001} restart: unless-stopped environment: - DATABASE_URL=${DATABASE_URL} - MCP_SERVER_PORT=${MCP_SERVER_PORT:-3001} - NODE_ENV=production stdin_open: true expose: - "${MCP_SERVER_PORT:-3001}" healthcheck: test: - CMD-SHELL - "pgrep -f 'node.*dist/index\\.js' > /dev/null || exit 1" interval: 30s timeout: 5s retries: 3 start_period: 25s networks: - echodo networks: echodo: driver: bridge