version: '3.8' services: # MySQL 数据库 # # ⚠️ 密码通过环境变量传入,必须从 .env 文件提供。首次部署前: # 1. cp .env.example .env # 2. 编辑 .env 把 DB_ROOT_PASSWORD / DB_PASSWORD 改成强密码 # 未设置会直接在 `docker compose up` 时报错,避免把默认密码带到生产环境。 mysql: image: mysql:8.0 container_name: mateclaw-mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:?DB_ROOT_PASSWORD is required in .env} MYSQL_DATABASE: ${DB_NAME:-mateclaw} MYSQL_USER: ${DB_USERNAME:-mateclaw} MYSQL_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required in .env} TZ: Asia/Shanghai ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql # Schema and seed data are managed by Flyway on application startup. # Do NOT mount legacy schema.sql / data.sql here — Flyway creates all # tables from V1 baseline and applies incremental migrations automatically. command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5 # SearXNG 搜索引擎(keyless 搜索 provider) # # The custom image at docker/searxng/ bakes in settings.yml so the sidecar # works out of the box (upstream image ships JSON disabled + Limiter enabled, # both of which silently break mateclaw's SearXNGSearchProvider). # No host bind-mount — edit docker/searxng/settings.yml and rebuild. searxng: build: context: ./docker/searxng container_name: mateclaw-searxng restart: unless-stopped environment: - SEARXNG_BASE_URL=http://searxng:8080 - SEARXNG_SECRET=${SEARXNG_SECRET:-mateclaw-dev-searxng-secret-change-me} - UWSGI_WORKERS=2 - UWSGI_THREADS=4 ports: - "8088:8080" healthcheck: # Healthz needs json format, so this also doubles as an integration check. test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/healthz"] interval: 30s timeout: 5s retries: 3 # MateClaw 后端服务 mateclaw-server: build: context: . dockerfile: mateclaw-server/Dockerfile args: MAVEN_FLAGS: ${MAVEN_FLAGS:-} container_name: mateclaw-server restart: unless-stopped depends_on: mysql: condition: service_healthy searxng: condition: service_healthy environment: SPRING_PROFILES_ACTIVE: mysql DB_HOST: mysql DB_PORT: 3306 DB_NAME: ${DB_NAME:-mateclaw} DB_USERNAME: ${DB_USERNAME:-mateclaw} DB_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required in .env} # LLM provider keys (DashScope / OpenAI / Anthropic / DeepSeek / Kimi / …) are # NOT configured via env vars. After startup, add providers in the admin UI: # Settings → Models → Add Provider # Keys are stored in mate_model_provider and hot-reloaded. SERPER_API_KEY: ${SERPER_API_KEY:-} JWT_SECRET: ${JWT_SECRET:-} MATECLAW_CORS_ALLOWED_ORIGINS: ${MATECLAW_CORS_ALLOWED_ORIGINS:-} # SearXNG: tell the app where to reach the sidecar container SEARXNG_BASE_URL: ${SEARXNG_BASE_URL:-http://searxng:8080} # Browser automation: the runtime image (mcr.microsoft.com/playwright:*) # bakes Chromium + system libs + fonts in, so the tool works out of the box. # Override these if you want to attach to an external Chrome (CDP sidecar): MATECLAW_BROWSER_CDP_URL: ${MATECLAW_BROWSER_CDP_URL:-} MATECLAW_BROWSER_CHROME_PATH: ${MATECLAW_BROWSER_CHROME_PATH:-} MATECLAW_BROWSER_CHANNEL: ${MATECLAW_BROWSER_CHANNEL:-} # OAuth 模式默认保持 auto:localhost 访问走 LOCAL,IP/域名访问走 DEVICE_CODE。 # 本机 Docker 若要强制使用 localhost:1455 回调,可在 .env 显式设为 local。 MATECLAW_OAUTH_OPENAI_DEPLOYMENT_MODE: ${MATECLAW_OAUTH_OPENAI_DEPLOYMENT_MODE:-} MATECLAW_OAUTH_OPENAI_CALLBACK_BIND_HOST: ${MATECLAW_OAUTH_OPENAI_CALLBACK_BIND_HOST:-0.0.0.0} # Chromium needs a real /dev/shm. Docker defaults to 64MB which causes # SIGBUS / "Target page closed" errors under load. 2GB is the usual # recommendation for Playwright / headless chrome. shm_size: 2gb ports: - "18080:18088" # host:container — app listens on 18088 inside the container - "1455:1455" volumes: - server_data:/app/data volumes: mysql_data: server_data: