首页
/ Multica 自托管实战:面向 AI Agent 的两步本地部署、CLI 接入与端口排障全解

Multica 自托管实战:面向 AI Agent 的两步本地部署、CLI 接入与端口排障全解

2026-09-05 21:39:57作者:郦嵘贵Just

本篇基于仓库中的 SELF_HOSTING_AI.md 展开,完整讲解如何用两条命令在一台装有 Docker 的机器上拉起 Multica 自托管服务(前端 3000 端口 + 后端 8080 端口 + PostgreSQL),把 multica CLI 接入本地服务器并启动 agent daemon,以及端口冲突时如何正确改端口、如何用健康检查接口定位故障。读完后你既能手动复现整个部署链路,也能理解安装脚本、Makefile 与 CLI 在端口解析、凭证生成、登录探针等细节上的真实实现。

一、适用场景与前置条件

SELF_HOSTING_AI.md 的定位很明确:这份文档是为 AI agent 设计的执行手册——"Follow these steps exactly to deploy a local Multica instance and connect to it"。步骤高度确定、可机器执行,因此对人类用户同样是一份可靠的本地部署清单。它解决的是"在一台开发机上跑起一套完整可用的 Multica"这件事,而不是生产集群部署(Kubernetes/Helm 方案见 SELF_HOSTING.md)。

前置条件共三项:

  • 已安装 DockerDocker Compose(服务全部以容器方式运行);
  • 已安装 Homebrew(用于安装 CLI,macOS 上最常用);
  • PATH 上至少有 一个 AI agent CLI,文档点名 claudecodex——daemon 启动后会探测本机安装的 agent CLI 并向服务器注册,没有可探测到的 agent,daemon 虽能运行但没有可执行任务的运行时。

二、推荐路径:安装脚本两步部署

2.1 部署命令

# 安装 CLI + 拉起自托管服务器
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --with-server

# 为 CLI 配置 localhost、完成认证并启动 daemon
multica setup self-host

关键纪律是时序:必须等待安装脚本输出 ✓ Multica server is running and CLI is ready! 之后再运行 multica setup self-host。预期结果是三个可验证的状态:

  • 前端位于 http://localhost:3000;
  • 后端 API 位于 http://localhost:8080;
  • multica CLI 已安装且配置指向 localhost。

2.2 安装脚本内部到底做了什么

阅读 scripts/install.sh 可以确认 --with-server 模式(run_with_server)的完整执行链:

  1. 环境检测detect_os 只支持 Darwin/Linux(Windows 会直接提示改用 PowerShell 版安装器);check_docker 既检查 docker 命令存在,也用 docker info 确认守护进程正在运行。
  2. 检出服务器资产setup_server 把仓库浅克隆到 ~/.multica/server(可用环境变量 MULTICA_INSTALL_DIR 覆盖),默认检出的 ref 由 get_selfhost_ref 决定——优先 MULTICA_SELFHOST_REF,否则取最新 release tag,再退到 main。已有安装目录则复用并更新,而非重新克隆。
  3. 生成 .env:若不存在,则从 .env.example 复制并用 openssl 生成随机 JWT_SECRET(hex 32)与 POSTGRES_PASSWORD(hex 24),同时用正则同步 DATABASE_URL 中的密码。JWT_SECRET 是硬性要求——docker-compose.selfhost.yml 中写作 ${JWT_SECRET:?JWT_SECRET must be set...},缺失时 Compose 直接拒绝启动。
  4. 拉取官方镜像并启动docker compose -f docker-compose.selfhost.yml pull 拉取 GHCR 上的官方镜像;若所选 tag 尚未发布,脚本会明确提示改用 docker compose ... -f docker-compose.selfhost.build.yml up -d --build 从源码构建。随后 up -d 启动 postgres、backend、frontend 三个服务。
  5. 端口回读(关键设计)compose_published_port 通过 docker compose -f docker-compose.selfhost.yml port backend 8080 读取 Compose 实际发布的宿主端口,而不是从 .env 重新推导。脚本注释给出了原因:Compose 的插值让调用进程环境变量优先于 .env,任何只从文件推导端口的做法都可能探测到错误端口。健康检查与最终打印的 URL 共用这一次回读结果,二者永不失配。
  6. 健康等待:循环最多 45 次、每次 2 秒探测 http://localhost:<backend_port>/health,成功才打印 ✓ Multica server is running
  7. 安装 CLI:优先走 Homebrew(brew tap multica-ai/tap + brew install multica-ai/tap/multica),失败则回退到 GitHub Releases 二进制下载,安装位置按 /usr/local/binsudo~/.local/bin 依次回退。已安装时还会比较 multica version 与最新 release tag,自动升级。

--stop 模式则是 docker compose down 安装目录下的服务并执行 multica daemon stop,与第六节的停止操作对应。

三、替代路径:手动分步部署

git clone https://github.com/multica-ai/multica.git
cd multica
make selfhost
brew install multica-ai/tap/multica
multica setup self-host

Makefileselfhost 目标的行为(第 82–113 行):

  • .env 不存在,从 .env.example 复制并生成三个随机密钥:JWT_SECRETPOSTGRES_PASSWORD,以及 SELF_HOSTING_AI.md 未提及但 Compose 文件实际需要的 MULTICA_VCS_SECRET_KEY(自托管 Git 集成 docker-compose.selfhost.ymlMULTICA_VCS_INTEGRATION_ENABLED 默认为 true);
  • 拉取官方镜像;若 pull 失败(例如所选 MULTICA_IMAGE_TAG 尚未在 GHCR 发布),会提示回退到 make selfhost-build,后者用本地 multica-backend:dev / multica-web:dev 标签从当前检出构建,不会覆盖已拉取的 :latest 镜像;
  • 启动后调用 scripts/selfhost-wait.sh 等待并打印连接信息。

scripts/selfhost-wait.sh 的注释值得细读,它解释了端口链路的完整优先级:容器内部恒定监听 8080/3000,宿主发布端口按 BACKEND_PORT → API_PORT → SERVER_PORT → PORT 的别名顺序取值(docker-compose.selfhost.yml 第 61 行的 ${BACKEND_PORT:-${API_PORT:-${SERVER_PORT:-${PORT:-8080}}}} 即为实现)。脚本坚持用 docker compose port 回读实际发布端口,因为历史上"探测用的变量"与"Compose 发布的变量"不一致,导致健康堆栈被报告为仍在启动。

四、multica setup self-host 的四步语义与源码实现

文档明确该命令完成四件事:

  1. 把 CLI 配置为连接 localhost:8080 / localhost:3000
  2. 打开浏览器登录——使用邮件验证码,或在未配置 Resend 时使用后端日志中打印的生成码;
  3. 自动发现 workspace;
  4. 后台启动 daemon。

对照 server/cmd/multica/cmd_setup.go,有几个实现细节决定了它的可预期性:

  • URL 解析顺序resolveSelfHostServerURL 依次取 --server-url 标志 → MULTICA_SERVER_URL 环境变量 → 已有配置中的 server_url → 由 --port(默认 8080)拼出的 localhost 兜底。app_url 同理取 --app-urlMULTICA_APP_URL → 已有配置(除非传了 --frontend-port)。这意味着重复运行 setup self-host(例如重新登录)会保留已配置的远端部署,而不是悄悄重置回 localhost。
  • 远端部署必须显式给前端地址:当 server URL 指向非本机时,CLI 不会去猜 api.x.co 对应的 app.x.co,而是交互式提示输入(或要求 --app-url),避免把错误推迟到浏览器登录环节才暴露。
  • 先探活、后落盘persistSelfHostConfigIfReachable 用 2 秒超时的 GET /health 探活,只有服务器应答才覆写配置。一次失败的 setup self-host 绝不会清掉可用的配置和已保存的 token——这是针对旧版"先写配置再探测、失败即清空 token"行为的修正。
  • daemon 的启动/重启决策:setup 完成后 runDaemonAfterSetup 先探测该 profile 的 daemon 健康端口。若 daemon 正在运行且有活动任务,它不会重启 daemon(以免取消进行中的工作),而是提示"等待任务结束后手动执行 multica daemon restart 以应用新配置";无活动任务则自动重启,未运行则首次启动。这解释了为什么有时 setup 后需要手动 multica daemon restart

验证命令(与文档一致):

multica daemon status

正常输出为 running 并列出检测到的 agent。

五、停止服务

# 停止 daemon(本地进程,不在 Docker 内)
multica daemon stop

# 停止所有 Docker 服务
cd multica
make selfhost-stop

Makefileselfhost-stop 就是 docker compose -f docker-compose.selfhost.yml down;若当初用的是安装脚本,等价的官方入口是 install.sh | bash -s -- --stop(它会 down ~/.multica/server 下的 Compose 栈并尝试停 daemon)。注意数据卷 pgdatabackend_uploadsdocker-compose.selfhost.yml 声明,down 不会删除它们——重新 up 后数据仍在。

六、自定义端口:变量优先级是唯一的坑

当默认端口(8080/3000)被占用时,文档给出的三步是:

  1. 编辑 .env,修改 PORTFRONTEND_PORT。这些是宿主端口;容器内部恒定监听 8080/3000,因此改端口无需重新构建镜像
  2. 运行 make selfhost
  3. 运行 multica setup self-host --port <PORT> --frontend-port <FRONTEND_PORT>

文档专门警告了一个极易踩中的优先级陷阱,Makefiledocker-compose.selfhost.yml.env.example 三方注释可交叉印证:

  • make selfhost:Makefile 是 include .env 文件的,所以文件里的值压过 shell 环境变量——PORT=9100 make selfhost.env 已设 PORT 时会被忽略;而命令行赋值 make selfhost PORT=9100 则生效(Make 变量覆盖机制)。
  • 直接 docker compose 时优先级反过来:调用进程的环境变量压过 .env 文件。
  • 所以文档的建议是"改文件,而不是依赖环境变量"。

别名规则同样来自 Compose 文件的插值链:BACKEND_PORT 是覆盖后端端口的可选别名,其后依次是 API_PORTSERVER_PORT,最后才是 PORT——前者优先级更高。无论走哪条路径,make selfhost(经 scripts/selfhost-wait.sh)与安装脚本都会从 Docker Compose 回读实际发布的端口,因此启动输出里打印的地址就是栈真正对外暴露的地址,不存在"打印 8080、实际监听 9100"的错位。

七、故障排查

文档给出四条对症命令:

症状 排查命令
后端未就绪 docker compose -f docker-compose.selfhost.yml logs backend
前端未就绪 docker compose -f docker-compose.selfhost.yml logs frontend
daemon 异常 multica daemon logs
存活/就绪检查 curl http://localhost:8080/health(liveness)、curl http://localhost:8080/readyz(依赖感知 readiness)

结合 Compose 文件可以补充两个判断依据:postgres 带 pg_isready 健康检查且 backend 声明 depends_on: postgres: condition: service_healthy,所以"backend 反复重启/起不来"优先查数据库容器是否 healthy;backend 启动时会自动执行迁移(SELF_HOSTING.md 说明迁移在后端启动时自动运行),冷启动慢时看 backend 日志即可。/readyz/health 的区别在于前者会检查依赖(如数据库连通性)是否就绪,安装脚本的探活循环用的就是 /health

八、延伸阅读

一句话总结部署心智模型:Docker 栈只负责服务器三件套(postgres/backend/frontend,宿主端口可配、容器端口恒定),multica CLI 与 daemon 永远跑在宿主机上——前者通过 setup self-host 指向后端 URL 完成认证与注册,后者探测本机 agent CLI 并等待任务。端口、凭证、探活这三个环节的任何异常,都能用第二节的回读机制与第七节的检查命令快速定位。

登录后查看全文
热门项目推荐
相关项目推荐