# ============================================================================ # ⚠️ DATABASE ENGINE: PostgreSQL (was MySQL before) # # This stack now runs on PostgreSQL 16. Switching the DB engine is a BREAKING # change for existing deployments: `docker compose up -d` on a host that # previously ran the MySQL stack starts a FRESH, EMPTY PostgreSQL volume # (postgres_data). The old `mysql_data` volume is NOT read and the app # re-seeds default data — existing data is not lost, but it is also NOT # visible to the new stack. # # Treat this as FRESH-INSTALL-ONLY. To carry data across from a MySQL # deployment, dump the OLD stack BEFORE pulling this change, e.g.: # docker compose exec mysql mysqldump -u"$DB_USERNAME" -p"$DB_PASSWORD" "$DB_NAME" > mateclaw-mysql.sql # then load into PostgreSQL with a cross-engine tool such as pgloader — # there is no automatic MySQL → PostgreSQL migration here. Alternatively, # keep running MySQL by pinning your checkout to a pre-switch tag and setting # SPRING_PROFILES_ACTIVE=mysql (the mysql Spring profile remains supported). # ============================================================================ services: # PostgreSQL 数据库 # # ⚠️ 密码通过环境变量传入,必须从 .env 文件提供。首次部署前: # 1. cp .env.example .env # 2. 编辑 .env 把 DB_ADMIN_PASSWORD / DB_PASSWORD 改成强密码 # 未设置会直接在 `docker compose up` 时报错,避免把默认密码带到生产环境。 postgres: image: postgres:16 container_name: mateclaw-postgres restart: unless-stopped environment: # Bootstrap/superuser — owns the cluster, used only for init + admin tasks. POSTGRES_DB: ${DB_NAME:-mateclaw} POSTGRES_USER: ${DB_ADMIN_USERNAME:-mateclaw_admin} POSTGRES_PASSWORD: ${DB_ADMIN_PASSWORD:?DB_ADMIN_PASSWORD is required in .env} # Least-privilege application role created by the init script below; this # is the account the server connects with (NOT a superuser). APP_DB_USERNAME: ${DB_USERNAME:-mateclaw} APP_DB_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required in .env} TZ: Asia/Shanghai # No host port on purpose — the DB is only reachable from the compose # network. For ad-hoc inspection use `docker compose exec postgres psql`, # or temporarily add: ports: ["127.0.0.1:5432:5432"] volumes: - postgres_data:/var/lib/postgresql/data # Runs once on first init (empty data dir): creates the restricted app # role and the mateclaw schema it owns. See docker/postgres/init/. - ./docker/postgres/init:/docker-entrypoint-initdb.d:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DB_ADMIN_USERNAME:-mateclaw_admin} -d ${DB_NAME:-mateclaw}"] interval: 10s timeout: 5s retries: 5 networks: - mateclaw-net # 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. # Internal-only: the app reaches it via the compose network. To debug from # the host, temporarily add: ports: ["127.0.0.1:8088:8080"] 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 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 networks: - mateclaw-net # MateClaw 后端服务 mateclaw-server: build: context: . dockerfile: mateclaw-server/Dockerfile args: MAVEN_FLAGS: ${MAVEN_FLAGS:-} container_name: mateclaw-server restart: unless-stopped depends_on: postgres: condition: service_healthy searxng: condition: service_healthy environment: SPRING_PROFILES_ACTIVE: postgres DB_HOST: postgres DB_PORT: 5432 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:-} TAVILY_API_KEY: ${TAVILY_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:-} # SSRF / TLS relaxations for isolated LAN / on-prem deployments. # Both default to false (strict mode, public-internet safe). # The .env file uses the PLAYWRIGHT_* prefix (component-oriented naming, # not product-oriented) — here we translate to the MATECLAW_BROWSER_* # container env that Spring Boot relaxed-binding maps to BrowserProperties. # - PLAYWRIGHT_ALLOW_PRIVATE_NETWORK=true: allow loopback / private / link-local # addresses through the browser SSRF guard. Cloud-metadata endpoints stay # blocked. Turn on when the agent must drive http://192.168.x.x:port style # internal services and has no path to the public internet. # - PLAYWRIGHT_IGNORE_HTTPS_ERRORS=true: ignore HTTPS certificate errors. # Auto-enables --ignore-certificate-errors at the Chromium command line # when ALLOW_PRIVATE_NETWORK is also true (so CDP-attached external # browsers benefit too). Leave false on internet-facing deployments. MATECLAW_BROWSER_ALLOW_PRIVATE_NETWORK: ${PLAYWRIGHT_ALLOW_PRIVATE_NETWORK:-false} MATECLAW_BROWSER_IGNORE_HTTPS_ERRORS: ${PLAYWRIGHT_IGNORE_HTTPS_ERRORS:-false} # Playwright action / navigation timeouts (seconds). Increase for slow # LAN or large-page scenarios. Defaults match Playwright's own (30s). MATECLAW_BROWSER_DEFAULT_TIMEOUT_SECONDS: ${PLAYWRIGHT_DEFAULT_TIMEOUT_SECONDS:-30} MATECLAW_BROWSER_DEFAULT_NAVIGATION_TIMEOUT_SECONDS: ${PLAYWRIGHT_NAVIGATION_TIMEOUT_SECONDS:-30} # Hard cap on the textual snapshot returned by action=snapshot. Content # beyond this length is dropped with a truncated:true flag and a hint to # retry with selector. Results > framework spill threshold (~8000 chars) # are further spilt to disk by ToolResultStorage. MATECLAW_BROWSER_SNAPSHOT_MAX_LENGTH: ${PLAYWRIGHT_SNAPSHOT_MAX_LENGTH:-20000} # 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} # Wiki 知识库目录扫描白名单(逗号分隔,留空则禁止所有目录扫描)。 # 示例:MATE_WIKI_ALLOWED_SOURCE_ROOTS=/data/wiki,/opt/docs # 记得同步在 volumes 里把宿主机路径挂进容器。 MATE_WIKI_ALLOWED_SOURCE_ROOTS: ${MATE_WIKI_ALLOWED_SOURCE_ROOTS:-} # Wiki 知识源自动同步总开关(运维总闸,默认关)。AND 语义:全局开关与 # 每个知识库自己的「自动同步」开关都开,该库才会被定时扫描。 # 间隔单位毫秒,默认 5 分钟。 MATE_WIKI_WATCHER_ENABLED: ${MATE_WIKI_WATCHER_ENABLED:-false} MATE_WIKI_WATCHER_INTERVAL_MS: ${MATE_WIKI_WATCHER_INTERVAL_MS:-300000} # Skill 工作区根目录。放在 /app/data 下,让现有的 server_data 卷一并持久化 # 已安装的 skill、运行时积累的 LESSONS.md 以及 skill 运行产物,容器重启不丢。 # 内置 skill 仍由 JAR classpath 每次启动现场释放,空卷不会丢内置文件。 MATECLAW_SKILL_WORKSPACE_ROOT: ${MATECLAW_SKILL_WORKSPACE_ROOT:-/app/data/skills} # Skill ZIP 上传/安装大小上限(MB)。解包过程整包缓存在内存里, # max-total 调多大,单次安装的峰值内存就可能吃多大。 MATECLAW_SKILL_UPLOAD_MAX_ENTRY_SIZE_MB: ${MATECLAW_SKILL_UPLOAD_MAX_ENTRY_SIZE_MB:-1} MATECLAW_SKILL_UPLOAD_MAX_TOTAL_SIZE_MB: ${MATECLAW_SKILL_UPLOAD_MAX_TOTAL_SIZE_MB:-50} # pip 镜像源配置(可选)。skill 里的 Python 脚本缺包时 pip install 会走这个源。 # 留空则用 PyPI 默认源(pypi.org)。pip 原生读 PIP_INDEX_URL / PIP_TRUSTED_HOST # 环境变量,容器内所有进程(JVM、Python 子进程、bash)自动继承,无需额外配置。 # HTTP 源会自动从 URL 推导 PIP_TRUSTED_HOST;自签 HTTPS 需手动填。 # - 互联网加速:PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple # - 局域网私有源:PIP_INDEX_URL=http://192.168.1.100:8080/simple(trusted-host 自动推导) PIP_INDEX_URL: ${PIP_INDEX_URL:-} PIP_TRUSTED_HOST: ${PIP_TRUSTED_HOST:-} # 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 covers /app/data — wiki-uploads AND the skill workspace # (MATECLAW_SKILL_WORKSPACE_ROOT=/app/data/skills above), so a single # volume persists everything. No separate skills volume needed. - server_data:/app/data networks: - mateclaw-net volumes: postgres_data: server_data: networks: mateclaw-net: driver: bridge