mirror of
https://github.com/multica-ai/multica.git
synced 2026-08-04 17:18:35 +02:00
* docs(self-host): explain loopback-only bindings + reverse proxy guidance (MUL-2360) Follow-up to #2759, which bound all docker-compose published ports to 127.0.0.1. The self-host quickstart still told cross-machine users to point their CLI at `http://<server-ip>:8080`, which no longer works (and shouldn't — the default JWT_SECRET/Postgres creds must not be reachable from the open internet). - Add a Callout to step 1 explaining the loopback-only bindings and linking to the new reverse-proxy step. - Split step 5 into 5a (same machine, defaults) and 5b (cross-machine), with a minimal Caddyfile that fronts both frontend and backend on a single hostname (including the `/ws` route with `flush_interval -1`). Switch the cross-machine `--server-url` example to `https://<domain>`. - Mirror the changes in the Chinese quickstart. - Add a header comment block to docker-compose.selfhost.yml so anyone reading the file directly understands why services don't show up on `0.0.0.0` and what to do about it. Co-authored-by: multica-agent <github@multica.ai> * docs(self-host): use nginx highlighter for Caddyfile snippet Shiki's default bundle does not include `caddy` / `caddyfile`, so Vercel's `pnpm build` failed with: ShikiError: Language `caddy` is not included in this bundle. Switch the code fence to `nginx`, which is in the default bundle and gives near-identical visual highlighting for this snippet. No content changes — the Caddyfile inside the block is untouched. Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: multica-agent <github@multica.ai>
170 lines
8.4 KiB
Plaintext
170 lines
8.4 KiB
Plaintext
---
|
||
title: Self-Host 快速上手
|
||
description: 在自己的服务器或本机用 Docker 把 Multica 跑起来。约 10 分钟。
|
||
---
|
||
|
||
import { Callout } from "fumadocs-ui/components/callout";
|
||
|
||
这一页带你用 Docker 把 Multica 的**服务器**(后端 + 前端 + PostgreSQL)跑在自己的机器或服务器上。走完这一篇你的数据就完全在自己手里——包括 [工作区](/workspaces)、[issue](/issues)、[评论](/comments)、[智能体](/agents) 配置。
|
||
|
||
智能体**执行**还是靠你本地跑的 [守护进程](/daemon-runtimes) + 本地装好的 [AI 编程工具](/providers)——这点和 Cloud 完全一样。Self-host 换掉的是服务器那一层,不是执行那一层。
|
||
|
||
## 前置要求
|
||
|
||
- **Docker** 安装好并且能跑 `docker compose`
|
||
- **Git** 可选(推荐——可以拉源码)
|
||
- 一台能长期开机的机器(本地 / 内网 / 云主机都行)
|
||
- 至少一款 AI 编程工具装在**运行守护进程的机器上**(不一定是跑服务器的机器——可以是你开发用的笔记本)
|
||
|
||
## 1. 拉取项目 + 一键启动后端
|
||
|
||
```bash
|
||
git clone https://github.com/multica-ai/multica.git
|
||
cd multica
|
||
make selfhost
|
||
```
|
||
|
||
`make selfhost` 会:
|
||
|
||
1. 如果没有 `.env` 文件,从 `.env.example` 自动生成一份并**生成随机 JWT_SECRET**
|
||
2. 拉取官方 Docker 镜像(PostgreSQL、Multica backend、Multica frontend)
|
||
3. 用 `docker-compose.selfhost.yml` 启动全部服务
|
||
4. 等后端 `/health` 端点准备就绪
|
||
|
||
如果是启动完成后的生产探针,想让数据库或 migration 异常也体现为失败,请改用 `/readyz`。
|
||
|
||
后端容器启动时会**自动跑数据库 migration**(`docker/entrypoint.sh` 在启动 server 前执行 `./migrate up`)——你会在 backend 日志里看到 migration 输出。升级版本时同样自动处理。
|
||
|
||
<Callout type="info">
|
||
**镜像还没发布?** 如果 `make selfhost` 报拉不到镜像,可能是你在某个未发布的版本标签上。切到稳定版本或直接从源码构建:`make selfhost-build`。
|
||
</Callout>
|
||
|
||
启动完成后:
|
||
|
||
- **前端**:[http://localhost:3000](http://localhost:3000)
|
||
- **后端**:[http://localhost:8080](http://localhost:8080)
|
||
|
||
<Callout type="info">
|
||
**所有端口只监听 `127.0.0.1`。** `docker-compose.selfhost.yml` 把每个 publish 出来的端口都绑到 loopback —— `ss -tlnp` 不会看到 `0.0.0.0:8080`,外网/其它机器默认根本连不上。这是为了避免默认 `JWT_SECRET` 和 Postgres 凭据被直接暴露到公网。要做跨机访问,请用反向代理在前面终结 TLS,详见下方 [Step 5b —— 跨机访问:用反向代理把服务挡在前面](#5b-跨机访问用反向代理把服务挡在前面)。
|
||
</Callout>
|
||
|
||
## 2. 重要:保持生产安全配置
|
||
|
||
<Callout type="warning">
|
||
**`docker-compose.selfhost.yml` 默认把 `APP_ENV` 设成 `production`**,并让 `MULTICA_DEV_VERIFICATION_CODE` 为空,所以公网实例默认没有固定验证码。
|
||
|
||
只在本地或私有测试自动化里设置 `MULTICA_DEV_VERIFICATION_CODE`。如果在 `APP_ENV` 非 production 时启用了固定验证码,任何能请求验证码的人都能用这个固定值登录。详见 [登录与注册配置 → 固定本地测试验证码](/auth-setup#固定本地测试验证码)。
|
||
|
||
公网部署前一定检查 `.env` 里 `APP_ENV=production`,且 `MULTICA_DEV_VERIFICATION_CODE` 为空。
|
||
</Callout>
|
||
|
||
## 3. 配置邮件服务(可选但推荐)
|
||
|
||
如果不配邮件,用户无法通过邮件收到验证码;server 会把生成的验证码打印到 stdout。
|
||
|
||
支持两种发送通道,按部署环境二选一:
|
||
|
||
**Option A — Resend(公网/云端部署):**
|
||
|
||
1. 在 [Resend](https://resend.com/) 注册并拿一个 API key
|
||
2. 验证一个你控制的发件域名
|
||
3. 在 `.env` 里设:
|
||
|
||
```bash
|
||
RESEND_API_KEY=re_xxxxxxxxxxxx
|
||
RESEND_FROM_EMAIL=noreply@yourdomain.com
|
||
```
|
||
|
||
**Option B — SMTP relay(内网/自部署):**
|
||
|
||
适合内网无法访问 `api.resend.com`,或已经有内部邮件中继(Exchange、Postfix、自部署 SendGrid 等)的场景。同时设置时 `SMTP_HOST` 优先级高于 Resend。
|
||
|
||
```bash
|
||
SMTP_HOST=smtp.internal.example.com
|
||
SMTP_PORT=587 # 默认 25;STARTTLS 提交端口用 587
|
||
SMTP_USERNAME=multica # 留空则使用未认证 relay
|
||
SMTP_PASSWORD=...
|
||
RESEND_FROM_EMAIL=noreply@yourdomain.com # 同时作为 SMTP From: 头
|
||
```
|
||
|
||
之后重启:`docker compose -f docker-compose.selfhost.yml restart backend`。
|
||
|
||
更多 auth 配置(OAuth、注册白名单)以及完整的 SMTP 变量说明见 [登录与注册配置](/auth-setup) 和 [环境变量](/environment-variables)。
|
||
|
||
## 4. 首次登录 + 创建工作区
|
||
|
||
打开 [http://localhost:3000](http://localhost:3000):
|
||
|
||
- 输入你的邮箱
|
||
- 从你配置的邮件后端(Resend 或 SMTP relay)收到的邮件里拿验证码;两者都没配的话,从 server 容器的 stdout 里抄 `[DEV] Verification code` 这行
|
||
- 不要直接使用 `888888`;只有在非 production 私有实例上显式设置 `MULTICA_DEV_VERIFICATION_CODE=888888` 后它才会生效
|
||
- 登录后创建第一个工作区
|
||
|
||
## 5. 连接命令行工具到你自己的 server
|
||
|
||
命令行装法和 [Cloud 快速上手 → 2. 装命令行工具](/cloud-quickstart#2-装-multica-命令行工具) 一样——Homebrew / 脚本 / PowerShell 任选。
|
||
|
||
### 5a. 同一台机器
|
||
|
||
CLI 和 server 在同一台机器上时,默认参数就够用:
|
||
|
||
```bash
|
||
multica setup self-host
|
||
```
|
||
|
||
会自动连 `http://localhost:8080`(backend)+ `http://localhost:3000`(frontend),引导你在浏览器里登录、把 PAT 存到本地、**自动启动守护进程**。
|
||
|
||
### 5b. 跨机访问:用反向代理把服务挡在前面
|
||
|
||
因为 compose 默认只监听 `127.0.0.1`,从别的机器跑的 daemon 是连不上 `http://<server-ip>:8080` 的——这也是有意为之,否则默认 `JWT_SECRET` 等于直接暴露在公网。正确做法是在 server 上跑一个反向代理(Caddy / nginx / Cloudflare Tunnel),由它终结 TLS,再反代到 `127.0.0.1:8080`(backend)和 `127.0.0.1:3000`(frontend)。然后把 CLI 指到公开的 HTTPS 域名:
|
||
|
||
```bash
|
||
multica setup self-host \
|
||
--server-url https://<你的域名> \
|
||
--app-url https://<你的域名>
|
||
```
|
||
|
||
最小可用的 Caddyfile,单域名同时挂前后端(带 WebSocket 转发,daemon 和网页端都依赖):
|
||
|
||
```nginx
|
||
multica.example.com {
|
||
# WebSocket 路由——必须在 catch-all 之前
|
||
@ws path /ws /ws/*
|
||
handle @ws {
|
||
reverse_proxy 127.0.0.1:8080 {
|
||
flush_interval -1
|
||
}
|
||
}
|
||
|
||
# Backend API
|
||
handle /api/* {
|
||
reverse_proxy 127.0.0.1:8080
|
||
}
|
||
|
||
# 其它请求 → 前端
|
||
reverse_proxy 127.0.0.1:3000
|
||
}
|
||
```
|
||
|
||
代理起好之后,记得在 server 的 `.env` 里把 `FRONTEND_ORIGIN` 设成 `https://multica.example.com` 并重启后端,否则 WebSocket 的 origin 校验会把浏览器拒掉(见 [故障排查 → WebSocket 连不上](/troubleshooting#websocket-连不上))。
|
||
|
||
[Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) 也是不错的选择——它直接给一个公开域名 + TLS,host 上不用对外暴露任何端口。Nginx 也能做(分 `app.` / `api.` 两个域名 + `proxy_set_header Upgrade` 转 WebSocket),关键就是终结 TLS、并在 `/ws` 上转发 `Upgrade` 头。
|
||
|
||
## 6. 创建智能体 + 分配第一个任务
|
||
|
||
流程和 Cloud 一样——见 [Cloud 快速上手 → 5-6 步](/cloud-quickstart#5-创建智能体)。
|
||
|
||
## 常见问题
|
||
|
||
- **后端起不来**:看容器日志 `docker compose -f docker-compose.selfhost.yml logs backend`;常见是 `.env` 里 `DATABASE_URL` 或 `JWT_SECRET` 有问题
|
||
- **验证码收不到**:没配任何邮件后端(Resend 和 SMTP 都没设) → 从 `docker compose logs backend` 里找 `[DEV] Verification code`
|
||
- **WebSocket 连不上**:公网部署必须设 `FRONTEND_ORIGIN` 成你真实的前端域名;见 [故障排查 → WebSocket 连不上](/troubleshooting#websocket-连不上)
|
||
|
||
## 下一步
|
||
|
||
- [环境变量](/environment-variables) —— 完整 env 清单
|
||
- [登录与注册配置](/auth-setup) —— Resend / OAuth / 注册白名单详细配置
|
||
- [GitHub 集成](/github-integration) —— 连一个 GitHub App,让 PR 自动关联 issue、merge 时自动转 Done
|
||
- [故障排查](/troubleshooting) —— 遇到问题先来这里
|
||
- [桌面应用](/desktop-app) —— 可以通过 `~/.multica/desktop.json` 连接 Desktop;Web 前端 + CLI 仍然是最快的自部署路径
|