自部署(self-hosted)是 MagicFrog 控制面的部署模型。支持两种形态,共享同一条规则:没有托管服务,也没有其他部署拓扑。单文件服务端是主路径——一个下载的二进制、一个 SQLite 文件,不需要容器 runtime。Docker Compose 仍可作为可选替代。
快速开始——单文件服务端
三条命令即可拉起一个可用的控制面:
curl -fsSL https://www.magicfrog.ai/install-server | bash
chmod +x ~/.magicfrog/bin/magicfrog-server
MAGICFROG_PASSWORD='<server-api-password>' \
MAGICFROG_ADMIN_IDENTIFIER='admin@example.com' \
MAGICFROG_ADMIN_PASSWORD='<initial-admin-password>' \
MAGICFROG_FIELD_KEY='<64-hex-chars>' \
./magicfrog-server serve --hostname 0.0.0.0 --port 4096
安装器把二进制放进 ~/.magicfrog/bin——与 magicfrog 客户端 CLI 相同的位置。在该目录中运行,或把它加进你的 PATH;可用 --data <dir> 或 MAGICFROG_DATA_DIR 设置别的数据目录。
必需环境变量
四个变量全部必填——缺任何一个,服务端都会显式启动失败,而不是带着空凭据启动:
| 变量 | 含义 |
|---|---|
MAGICFROG_PASSWORD |
客户端 --server 连接密码 |
MAGICFROG_ADMIN_IDENTIFIER |
初始管理员(邮箱或用户名) |
MAGICFROG_ADMIN_PASSWORD |
初始管理员密码 |
MAGICFROG_FIELD_KEY |
字段加密密钥,64 个十六进制字符(openssl rand -hex 32) |
MAGICFROG_ADMIN_IDENTIFIER 与 MAGICFROG_ADMIN_PASSWORD 必须成对注入——只给其一会让服务端在启动时显式失败。MAGICFROG_FIELD_KEY 也可以改用 MAGICFROG_FIELD_KEY_FILE(卷/secret 挂载)提供;两者都设置时以直接值为准。
首次启动与初始管理员
首次启动时,服务端把一个以给定标识与初始密码的账号写入 SQLite,标记它 role=owner 并置上 must_change_password;账号已存在时跳过写入(重启不会覆盖它)。初始密码只属于部署状态,且一次性。
强制改密
用初始密码经 POST /v1/account/login 登录(/admin 的管理控制台登录是同一道门)。响应携带 mustChangePassword=true。
该标志置位期间,除登录与改密之外的每个业务端点都以 403 password_change_required 拒绝请求。客户端呈现改密界面而不是工作台。经 POST /v1/account/change-password 提交旧密码与新密码:服务端校验旧密码,把新密码以单向哈希存储(明文绝不落盘),并清除标志。初始密码就此作废。
范围:一台服务器
控制面刻意做成单服务器:它只在自己所在的主机上、经该主机的容器 runtime 托管创建并管理云电脑。没有远程 Docker daemon 设置(DOCKER_HOST 一类)、没有多主机节点资源池、没有跨机器调度或集群模式。持久化遵循同一条规则——一个 SQLite 文件,没有外部或共享数据库选项。完整边界见云电脑。
你用 CLI 自行登记的机器在这个范围之外:控制面通过它们主动外连的 daemon 连接向它们发送工具调用,但从不托管创建、启动、停止或销毁它们。
单文件服务端的可变状态存放在数据目录(MAGICFROG_DATA_DIR 或 --data;SQLite 数据库为 MAGICFROG_DB):
| 内容 | 位置 |
|---|---|
| SQLite 数据库 | <data>/magicfrog.db(MAGICFROG_DB) |
| 数据 / 状态 / 缓存 / 配置 | <data>/xdg/{data,state,cache,config} |
| CLI 凭据 | <data>/.magicfrog/credentials |
字段加密密钥
MAGICFROG_FIELD_KEY 加密服务端仍需按精确值检索的个人数据:账号标识(邮箱或用户名)、登记设备名与计算机名。加密后登录与查找照常工作,而明文永不落库。
- 每个部署单独生成一个:
openssl rand -hex 32(64 个十六进制字符,32 字节)。 - 与数据目录一起存放,不放进镜像:和其他 secret 在同一处 export,或经
MAGICFROG_FIELD_KEY_FILE从你的 secret 存储挂载进来(两者都设置时直接值优先)。 - **密钥缺失、为空、不是 32 字节或文件不可读时,启动失败。**服务端绝不回落成明文存储这些列。这个失败即关闭(fail-closed)的行为是刻意的。
- **密钥丢失,被加密的列无法恢复。**请随数据目录一起备份。
- **轮换密钥需要对存量数据重新加密。**迁移完成之前保留旧密钥可用;用错误的密钥启动会直接失败,不会给出误导性结果。
数据如何加密存储
没有任何一类敏感值以明文落库:
- 账号密码、会话 token、设备 token 与配对码:只存单向哈希,无法还原原文。
- 账号标识、登记设备名与计算机名:用
MAGICFROG_FIELD_KEY加密存储(登录与查找照常工作)。
客户端本地的设备凭据文件(~/.magicfrog/credentials/device.json)受 0600 文件权限保护。审计记录与日志永不携带明文凭据或密钥。
Docker Compose(可选路径)
Compose 把同一个服务端跑成容器:单个 magicfrog 服务,背后是 Docker 命名卷上的 SQLite 数据库。镜像来自 GHCR 发布面 ghcr.io/gsc-org/magicfrog:<version>——GHCR 上的镜像发布目前不在现行发布面内,将另行公告;在此之前请使用单文件服务端。持久化与备份是卷操作:用 docker volume inspect magicfrog_magicfrog-data 找到数据在服务器上的位置。docker compose down 保留卷;down -v 删除卷。
Compose 首启导出与单文件相同的变量外加一个版本标签,然后启动栈:
export MAGICFROG_VERSION=<published-version> # a real GHCR release tag
export MAGICFROG_PASSWORD='<server-api-password>'
export MAGICFROG_ADMIN_IDENTIFIER='admin@example.com'
export MAGICFROG_ADMIN_PASSWORD='<initial-admin-password>'
export MAGICFROG_FIELD_KEY='<64-hex-chars>'
docker compose up -d
docker compose logs -f magicfrog
五个变量全部必填:Compose 对它们做严格插值,缺任何一个就报错退出,所以这个栈绝不会带着空凭据启动。端口默认 4096;用 MAGICFROG_PORT 覆盖主机端口映射。容器内部,所有可变状态都位于 /data 之下(映射到命名卷)。
下载与校验
已发布产物(magicfrog 客户端与单文件 magicfrog-server)从官方下载源分发。每个产物都附带 sha256 与 size 元数据;任何不一致都会拒绝安装,没有「照样安装但警告」的降级路径。
未签名产物
Windows 与 macOS 产物当前不做代码签名。SmartScreen 与 Gatekeeper 的「未知开发者」提示是操作系统行为,不是产品故障;选择「仍要运行」即可。
客户端发现
桌面或 web 客户端面对自部署启动时,显式解析服务端。未配置服务端时,它呈现未配置状态并提供服务端地址输入框,而不是静默继续。显式输入的服务端地址恒胜过自动发现。
管理控制台(/admin 管理面)需要在 console 构建时把 VITE_ADMIN_CONTROL_PLANE_URL 设为控制面源。变量未设置时,admin 登录门报告缺失配置,而不是把请求瞄准猜出来的源。console 与控制面不同源时,在服务端用 magicfrog serve --cors <origin> 放行 console 的源。
故障排查
| 症状 | 原因 / 处置 |
|---|---|
| 服务端启动失败,报告缺少必需变量 | MAGICFROG_PASSWORD / MAGICFROG_ADMIN_IDENTIFIER / MAGICFROG_ADMIN_PASSWORD / MAGICFROG_FIELD_KEY 之一未设置;见「必需环境变量」 |
首启日志报告 MAGICFROG_ADMIN_IDENTIFIER 与 MAGICFROG_ADMIN_PASSWORD 必须一起注入 |
两个 admin 变量只给了一个;成对注入 |
| 启动在字段加密密钥上失败 | MAGICFROG_FIELD_KEY 缺失、为空或非法——用 openssl rand -hex 32 生成一个;见「字段加密密钥」 |
业务端点返回 403 password_change_required |
强制改密尚未完成;见「强制改密」 |
docker compose up 报 set MAGICFROG_VERSION … |
某个必需变量未导出;见「Docker Compose」 |
| 创建云电脑返回 503,日志涉及 iptables 与 Permission denied | 服务器以非 root 用户运行,网络隔离规则装不上。要么以 root 运行,要么为 iptables 配置免密 sudo 并设置 MAGICFROG_POOL_HOST_COMMAND_PREFIX="sudo -n"。请求失败即关闭——修复后重试是安全的 |