# Plainleaf 极空间部署 Plainleaf 使用 Gitea Actions 自动发布。代码推送到 `main` 分支后会自动触发构建和 部署;也可以从 Gitea Actions 页面手动触发,用于发布失败后的重试。NAS 上的专用 Runner 在隔离 的 rootless Docker 中构建镜像,推送 `edge` 到 Gitea Registry,然后通过受限 SSH 密钥触发更新服务。不运行定时器,也不会轮询 Registry。 只有镜像 ID 变化时才会重建 `plainleaf` 容器,不会执行 `compose down`、Docker 清理或删除数据卷。 固定目录和端口: - 部署目录:`/data_s001/data/udata/real/13616066635/docker/plainleaf` - root 更新配置:`/etc/plainleaf` - 服务配置:`<部署目录>/data`,容器内为 `/data` - Markdown:`/data_s001/data/udata/real/13616066635/笔记管理/Plainleaf`,容器内为 `/notes` - NAS 端口:`31230` - 镜像:`gitea.aichickenfarm.cn/wushenghua/plainleaf:edge` Markdown 目录始终是数据真源,发布和更新都不会移动、重命名或改写已有文档。 ## 日常发布 启用 `push` 触发后,本机只需正常提交并推送代码: ```bash git push ``` Gitea Actions 会构建 `linux/amd64` 镜像并同时推送两个标签: - 当前 Git 短提交号,用于定位和人工回滚 - `edge`,供 NAS 自动更新 Mac 不需要安装 Runner,也不需要执行 `docker login`。Registry 令牌只保存在仓库 Actions Secret `REGISTRY_TOKEN` 中;NAS 部署私钥只保存在 `NAS_DEPLOY_KEY` 中。 ## NAS 首次启用 首次安装需要一次 SSH 和 `sudo`,之后日常发布不再上传镜像包,也不需要重复输入 SSH 或 `sudo` 密码。安装时要完成以下动作: 1. 将 `compose.yaml` 和现有 `.env` 复制到 root 持有的 `/etc/plainleaf`,配置 文件名为 `/etc/plainleaf/plainleaf.env`,并把 `PLAINLEAF_IMAGE_TAG` 设为 `edge`。更新服务只读取该目录,个人账号不能修改 root 更新流程。 2. 将 `update-plainleaf.sh` 安装为 `/usr/local/sbin/plainleaf-update`。 3. 将 systemd 单元安装到 `/etc/systemd/system/plainleaf-update.service`。 4. 生成专用的 `~/.ssh/plainleaf_zspace_ed25519`,将公钥安装到 NAS。授权行使用 forced-command,并禁用端口转发、Agent 转发、PTY 和 X11;这把密钥只能触发 Plainleaf 更新,不能登录 Shell。发布脚本还会开启 `BatchMode` 和 `IdentitiesOnly`,不会回退到密码或其他密钥。 5. 安装 `plainleaf-update.sudoers`,其中只有一条受限规则,只允许 NAS 账号免密启动 `plainleaf-update.service`,不能免密执行其他 root 命令。 6. 执行 `systemctl daemon-reload`,再手动启动一次服务,确认拉取、重建和健康检查 成功。服务不会常驻,只有本机发布脚本主动调用时才运行。 仓库内的 `install-update-service.sh` 会执行上述 NAS 安装步骤。它会先用 `visudo` 校验规则,保留现有 `.env` 的路径和 UID/GID,只把镜像标签改成 `edge`;脚本本身 不会拉取镜像、启动服务或重建容器。 部署 `.env` 不存放账号密码,保留以下字段: ```dotenv PLAINLEAF_IMAGE_TAG=edge PLAINLEAF_UID=1001 PLAINLEAF_GID=1001 PLAINLEAF_PORT=31230 PLAINLEAF_SERVER_PATH=/data_s001/data/udata/real/13616066635/docker/plainleaf/data PLAINLEAF_SPACE_PATH=/data_s001/data/udata/real/13616066635/笔记管理/Plainleaf ``` ## 更新与回滚行为 `plainleaf-update` 每次只做以下事情: 1. 验证 Compose 中只有 `plainleaf` 服务,且镜像来自固定 Gitea 仓库。 2. 给当前容器镜像保留 `rollback` 标签。 3. 仅执行 `docker compose pull plainleaf`。 4. 镜像 ID 未变化时直接退出;变化时仅重建 `plainleaf`。 5. 等待容器健康;失败时重新标记旧镜像并恢复旧容器。 新镜像启动失败时不会删除,方便后续排查。更新日志可通过以下命令只读查看: ```bash sudo systemctl status plainleaf-update.service sudo journalctl -u plainleaf-update.service -n 100 --no-pager ``` ## 账号模式初始化 空的 `/data` 会打开 `https:///.setup/`。首个空间建议使用: - 名称:`Plainleaf` - URL 路径:`/` - 数据目录:`/notes` 管理员可在 `/.spaces/users` 管理用户,在 `/.spaces` 分配空间访问权限。初始化和 更新都不会移动 Markdown;`users.json`、`spaces.json` 和会话密钥只写入 `/data`。 ## 人工回滚 自动回滚失败时,可把 `.env` 的 `PLAINLEAF_IMAGE_TAG` 改为之前发布的 Git 短提交 号,再仅重建 `plainleaf` 服务。不要删除 `/data`、`/notes`、Docker volume, 也不要运行 `docker system prune` 或 `docker compose down`。