自托管快速上手
用 Docker Compose 启动 Melso,完成登录,并连接第一台执行电脑。
自托管 Melso 分成两部分:
| 部分 | 运行什么 | 放在哪里 |
|---|---|---|
| Melso 服务 | Web、API 和 PostgreSQL | 一台安装了 Docker 的机器 |
| 执行电脑 | Melso 守护进程和 AI 编程工具 | 开发者实际工作的电脑 |
它们可以是同一台机器,也可以分开。自托管替换的只是 Melso Cloud 部分。
这篇文档使用 Docker Compose。Kubernetes 部署见仓库中的 Self-hosting guide。
开始前
运行 Melso 服务的机器需要:
- Docker Engine 或 Docker Desktop,并且
docker compose可以运行 - Git、Make、curl 和 OpenSSL
- 本机的
3000、8080端口未被占用
先确认 Docker 和 Compose 可用:
docker info
docker compose versionMelso 使用 Compose v2,也就是 docker compose。旧版的 docker-compose v1 不受支持。
执行电脑还需要至少一款已经安装并登录的 AI 编程工具,例如 Claude Code、Codex 或 Cursor。第 5 步再安装 Melso CLI。
1. 启动 Melso
在准备运行服务的机器上执行:
git clone --depth 1 https://github.com/albertsalgueda/melso.git
cd multica
make selfhost第一次运行时,make selfhost 会:
- 从
.env.example创建.env - 随机生成
JWT_SECRET、PostgreSQL 密码和MULTICA_VCS_SECRET_KEY(自托管 Git 集成的加密密钥) - 拉取 PostgreSQL、Melso backend 和 Melso frontend 镜像
- 创建持久化数据卷并启动三个容器
- 等待 backend 开始响应健康检查
之后再次运行 make selfhost 会继续使用现有的 .env 和数据卷,不会重新生成密钥。
make selfhost 拉取已发布的镜像,不会编译当前 checkout 中的代码。需要测试本地源码时,使用 make selfhost-build。
2. 确认服务已经就绪
查看容器状态:
docker compose -f docker-compose.selfhost.yml pspostgres 显示为 healthy,backend 和 frontend 应处于运行状态。然后检查 backend、数据库和 migration:
curl -fsS http://localhost:8080/readyz正常响应是:
{"status":"ok","checks":{"db":"ok","migrations":"ok"}}Backend 容器每次启动时都会先运行数据库 migration,再启动服务,不需要手动执行 migration 命令。
3. 选择访问方式
本机访问
直接打开 http://localhost:3000。后面运行 melso setup self-host 时也不需要传 URL。
远程访问
Docker Compose 默认只把 3000 和 8080 绑定到 127.0.0.1。不要直接改成 0.0.0.0 暴露到公网;使用带 HTTPS 的反向代理。
下面以两个域名为例:
app.example.com:Melso Webapi.example.com:API、健康检查和守护进程连接
先在 .env 中设置公开地址:
FRONTEND_ORIGIN=https://app.example.com
MULTICA_APP_URL=https://app.example.com
MULTICA_PUBLIC_URL=https://api.example.com以上配置让浏览器流量全部走 app 域,cookie 不跨域,因此不需要配置 COOKIE_DOMAIN。如果改为让浏览器直接访问 api 域,则必须配置它,见环境变量。
然后配置 DNS,并用 Caddy 代理本机端口:
app.example.com {
# 浏览器的 WebSocket 直接交给 backend
@ws path /ws /ws/*
handle @ws {
reverse_proxy 127.0.0.1:8080 {
flush_interval -1
}
}
# 其余路径交给 frontend;它会转发 API 和登录请求
handle {
reverse_proxy 127.0.0.1:3000
}
}
api.example.com {
reverse_proxy 127.0.0.1:8080 {
flush_interval -1
}
}Caddy 会申请 TLS 证书并转发 WebSocket。修改 .env 后,用 up -d 重新创建容器,让新配置生效:
docker compose -f docker-compose.selfhost.yml up -d
curl -fsS https://api.example.com/readyzdocker compose restart 只重启现有容器,不会重新读取 .env。修改配置后,重新读取 .env 需要运行 docker compose -f docker-compose.selfhost.yml up -d。
4. 登录并创建工作区
打开本机的 http://localhost:3000,或刚才配置的 https://app.example.com,输入邮箱获取验证码。
默认没有配置邮件服务。请求验证码后,可以从 backend 日志中读取:
docker compose -f docker-compose.selfhost.yml logs backend \
| grep "Verification code"日志中会出现类似内容:
[DEV] Verification code for you@example.com: 123456输入验证码并创建第一个工作区。配置 Resend 或 SMTP 后,验证码通过邮件发送,成员无需读取容器日志,具体见登录与注册配置。
自托管部署默认使用 APP_ENV=production,不会启用固定验证码。不要在公网实例上设置 MULTICA_DEV_VERIFICATION_CODE。
5. 连接执行电脑
下面的命令在运行 AI 编程工具的电脑上执行,不一定是运行 Docker 的服务器。
任务以运行守护进程的用户的全部权限执行——该用户能读写的一切,任务都能读写。请用专用 Unix 用户、容器或虚拟机来运行守护进程,而不是你的个人账号。详见安全模型。
先安装 Melso CLI:
macOS / Linux
curl -fsSL https://downloads.melso.ai/install.sh | bashWindows PowerShell
irm https://downloads.melso.ai/install.ps1 | iex如果 Melso 服务也在这台电脑上,运行:
melso setup self-host如果 Melso 服务在另一台机器上,传入刚才配置的两个地址:
melso setup self-host \
--server-url https://api.example.com \
--app-url https://app.example.com这条命令会先检查 <server-url>/health,再打开浏览器完成登录。登录完成后,它会保存本机凭据并启动守护进程。
确认连接状态:
melso daemon status正常情况下,输出中会显示:
Daemon: runningAgents中包含本机已安装的 AI 编程工具Workspaces大于0
6. 完成第一次执行
回到 Melso。运行时列表中出现在线的运行时后,创建一个智能体,并把第一个 issue 分配给它。
执行日志变为"已完成"、时间线中出现智能体的回复,说明自托管服务、执行电脑和 AI 编程工具已经连通。详细步骤见快速上手第 3-5 步。
常用管理命令
以下命令都在 multica 仓库目录中运行:
# 查看状态
docker compose -f docker-compose.selfhost.yml ps
# 查看 backend 日志
docker compose -f docker-compose.selfhost.yml logs -f backend
# 应用 .env 变化
docker compose -f docker-compose.selfhost.yml up -d
# 停止服务,保留数据卷
docker compose -f docker-compose.selfhost.yml down升级已发布的镜像:
git pull --ff-only
docker compose -f docker-compose.selfhost.yml pull
docker compose -f docker-compose.selfhost.yml up -d
curl -fsS http://localhost:8080/readyzDocker Compose 部署有两种升级写法。在已有部署上两者结果相同——Makefile 里的 selfhost target 跑的就是同一套 docker compose pull + up -d,只是额外多做了两件事:.env 缺失时生成一份,以及等 /health 就绪后打印一段状态汇总。用哪个都行:
cd multica
git pull
make selfhostcd multica
git pull
docker compose -f docker-compose.selfhost.yml pull
docker compose -f docker-compose.selfhost.yml up -dgit pull 到底更新了什么
git pull 更新的是 docker-compose.selfhost.yml 本身——新增的环境变量、新增的服务、改过的 healthcheck。它不是拉新版本 Melso 的机制。
真正决定你跑哪个版本的是 docker compose pull:它去 GHCR 查这个 tag 当前指向哪个镜像。所以一个几个月没更新的 checkout 照样能拉到今天的 latest 镜像;反过来,只跑 git pull 而不拉镜像、不重建容器,什么都不会变。
如果你在 .env 里钉死了 MULTICA_IMAGE_TAG,两种写法都升不上去。 两个镜像都写成 ${MULTICA_IMAGE_TAG:-latest}(docker-compose.selfhost.yml:42、:125),而 .env.example 里默认是 MULTICA_IMAGE_TAG=latest。一旦你把它改成了具体版本,pull 只是把同一个 tag 重拉一遍,版本原地不动——不报错,也没有任何警告。升级前先确认:
grep MULTICA_IMAGE_TAG .env
# MULTICA_IMAGE_TAG=v0.4.5 ← 钉死了:先改成 latest(或你想要的版本).env 不会被覆盖
make selfhost 只在 .env 不存在的时候才生成它。在已有部署上重复跑,你的 JWT_SECRET、Postgres 密码、邮件配置、FRONTEND_ORIGIN 都原样保留。
升级前先备份 Postgres
migration 只往前走、不回滚,所以正式环境升级前先导一份:
docker compose -f docker-compose.selfhost.yml exec -T postgres \
pg_dump -U multica multica > multica-backup.sql && gzip multica-backup.sql不要把 pg_dump 直接管道接给 gzip。 shell 取的是管道里最后一条命令的退出码,所以 pg_dump ... | gzip > backup.sql.gz 在导出失败时照样返回 0,留下一个格式完全合法、但里面什么都没有的 20 字节压缩包。先重定向到文件,pg_dump 自己的退出码才算数,&& 也只会压缩真正成功的那份导出。
如果你改过 POSTGRES_USER / POSTGRES_DB,把 multica 换成 .env 里的实际值。数据存在名为 multica_pgdata 的 volume 里,docker compose down 不会删它——但 down -v 会。
migration 自动执行
和第 1 步一样,backend 容器启动时会在对外提供服务之前先跑 ./migrate up(docker/entrypoint.sh)。没有单独的升级命令——把新镜像起起来,本身就是升级这一步。想看过程:
docker compose -f docker-compose.selfhost.yml logs -f backendMigration 在 backend 启动时自动运行;需要回填历史数据的 migration(如 103)也会自动完成回填。自动回填极少数情况下失败,报 refusing to drop legacy daily rollups,处理见故障排查。
用 /readyz 验证,不要用 /health
/health 是 liveness 探针,只要进程还活着就返回 {"status":"ok"},migration 失败了它照样是 ok。/readyz(server/cmd/server/router.go:680,/healthz 是它的别名)会真正检查数据库和已应用的 migration 集合,升级出问题能被它拦下来:
curl -s localhost:8080/readyz
# {"status":"ok","checks":{"db":"ok","migrations":"ok"}}只要不是 HTTP 200 且两项都是 ok,就说明新版本没把 migration 跑完,先去看 backend 日志,别急着放流量进来。
Kubernetes
Helm 有自己的升级路径:在 values 文件里把 images.backend.tag / images.frontend.tag 设成你要的版本,然后 helm upgrade。改 tag 就改了 pod spec,Kubernetes 会拉新镜像并滚动更新——这是可靠的路径。
kubectl -n multica rollout restart 本身不是升级。chart 默认 pullPolicy: IfNotPresent(deploy/helm/multica/values.yaml),节点上已经缓存过这个 tag 的话,restart 只会用回旧镜像,什么都没变——和钉死 MULTICA_IMAGE_TAG 是同一类坑。真要靠浮动 tag 走这条路,得先把 images.backend.pullPolicy / images.frontend.pullPolicy 设成 Always。详见仓库的 Self-hosting guide。
docker compose down 会保留 pgdata 和 backend_uploads。加上 -v 会删除这些数据卷,包括数据库;除非确定要清空实例,否则不要运行 docker compose down -v。
常见问题
| 现象 | 先检查什么 |
|---|---|
/readyz 没有返回 ok | 运行 docker compose -f docker-compose.selfhost.yml logs backend postgres。 |
| 收不到验证码 | 请求一次验证码,再从 backend 日志中查找 Verification code。 |
setup self-host 提示 server 不可达 | 在执行电脑上请求 https://api.example.com/health,确认 DNS、TLS 和反向代理都可达。 |
守护进程没有列出 Agents | 确认 AI 编程工具在 PATH 中并已登录,然后运行 melso daemon restart。 |
| issue 一直排队 | 运行 melso daemon status,确认守护进程正在运行并连接了工作区。 |
更多情况见故障排查。
接下来
- 登录与注册配置 — 配置邮件、Google 登录和注册范围。
- 环境变量 — 查看完整的服务端配置。
- Self-hosting guide — Kubernetes、升级和手动部署。
- 桌面应用 — 让 Desktop 连接自托管服务。