# 部署与运维

> 返回 [← README](../README.md)

数据持久化、常见问题排查、忘记超管密码的离线找回，以及仓库目录结构。

---

## 数据持久化

- **面板数据**（用户、实例元信息、密码哈希）：容器内 `/data`，映射到宿主 `./data-panel`。
- **每个微信实例**：独立的 docker 命名卷 `woc-data-<id>`，挂到该实例容器的 `/config`（微信本体在 `/config/wechat`，登录态与消息缓存在 `/config` 其余位置）。

要点：
- 删除实例**默认保留**其数据卷，下次同名重建可复用；只有显式勾选「彻底清除」才会删卷。
- 备份某实例 = 备份对应的 `woc-data-<id>` 卷（`docker volume` 系列命令）。
- 卷需支持执行权限（微信本体直接从卷里运行）；放在 `noexec` 卷上微信将无法启动。
- 备份面板 = 备份 `./data-panel`。

> **从旧版（单微信容器 + `./data` 绑定挂载）迁移**：旧形态把微信数据放在宿主 `./data`。新版用 docker 命名卷，结构不同，无自动迁移。如需保留旧会话，最简单是新建一个实例、重新扫码登录；或手动把旧 `./data` 内容拷进新实例的 `woc-data-<id>` 卷。

---

## 常见问题

| 现象 | 排查 |
|------|------|
| 新建实例失败 | 多为面板拉不到微信镜像或连不上 docker.sock。确认 `docker.sock` 已挂载、宿主能访问 GHCR；看面板日志 `docker logs woc-panel` |
| 界面/消息显示成方块 | 中文字体没装好，确认实例镜像含 `fonts-noto-cjk` |
| 微信起不来 / 黑屏 | 看实例日志 `docker logs woc-wx-<id>`；确认 `seccomp=unconfined` 与 `shm_size` 生效。微信 deb 漏声明的运行时依赖已在 Dockerfile 内置 |
| 排查缺哪个库 | `docker exec woc-wx-<id> ldd /config/wechat/opt/wechat/wechat`，看 `not found` 项补进 Dockerfile 依赖层 |
| 多人同时操作很乱 | 已内置「操作控制权」软锁：当前操作者每数秒心跳续约，其余端自动转为**只读遮罩**（仍可看画面），空闲超时（约 10s）自动释放，他人可点「申请控制」接管。仍建议同一时刻一人操作 |
| 过段时间掉登录 | 微信桌面会话会定期失效，需手机重新扫码（见技术方案 6.2） |
| 下载 / 更新微信失败 | 腾讯 CDN 偶发波动，重新点「下载并安装 / 更新」即可；脚本已内置主/备 CDN 自动回退 |
| 架构不支持报错 | 微信仅提供 x86_64 / arm64；其他架构下载时会在面板状态里报错 |
| 忘记超管密码 | 见下方「重置超管密码」离线找回 |

查看面板日志：`docker logs -f woc-panel`；查看某实例日志：`docker logs -f woc-wx-<id>`（实例 ID 可在面板看到，或 `docker ps | grep woc-wx`）。也可在面板的「管理」页或实例页点「查看日志」直接导出实例容器日志。

---

## 重置超管密码（离线找回）

管理员密码无法被他人重置，忘记时按以下步骤离线找回：

```bash
docker compose stop panel                 # 1) 先停面板，避免覆盖你的手动修改
```

2) 编辑 `./data-panel/accounts.json`，给对应用户对象加一行 `"resetPassword": true`：

```json
{
  "id": "...", "username": "admin", "role": "admin",
  "passwordHash": "...", "disabled": false,
  "resetPassword": true
}
```

```bash
docker compose up -d                       # 3) 启动，面板初始化时会重置该账号
```

> ⚠️ 重置逻辑只在面板**进程启动**时执行。若你没先 `stop` 而面板仍在运行，直接 `docker compose up -d` 会因「容器无变化」而空操作（输出 `Running` 而非 `Started`），重置不会发生。此时执行 **`docker compose restart panel`**（或 `docker restart woc-panel`）强制重启即可生效。

重启后该账号密码被重置为 `PANEL_ADMIN_PASSWORD`（即 `.env` 的 `WOC_PASSWORD`，默认 `wechat`），并自动**解禁**、清除该标记；用此密码登录后请立即在「修改密码」改掉。日志会打印 `[store] 已重置用户 '<用户名>' 的密码`。

---

## 目录结构

```
WechatOnCloud/
├── .github/workflows/
│   └── release.yml        # 打 tag / 发 Release 时构建多架构镜像并推送 GHCR
├── docker/                # 微信实例镜像（ghcr.io/<owner>/wechat-on-cloud）
│   ├── Dockerfile         # KasmVNC base + 中文字体 + 微信运行时依赖 + xdotool + IME 补丁（不打包微信本体）
│   ├── woc-www-patch.sh   # 构建期补丁：开启 KasmVNC IME 模式 + 修复 noVNC 中文输入（配合 woc-ime.pl）
│   ├── woc-ime.pl         # noVNC 键盘 IME 逻辑的 perl 补丁（合成提交时整串发送，规避丢字）
│   ├── wechat-ctl.sh      # 运行时下载/解压/更新微信（面板经 docker exec 触发，状态写 /config/.woc-state）
│   ├── autostart          # openbox 会话启动：常驻拉起微信（崩溃自重启）+ 最小化窗口自动复原看守
│   └── woc-update-autostart  # 启动钩子：每次启动用镜像内最新 autostart 覆盖数据卷旧副本
├── panel/                 # 自研面板（ghcr.io/<owner>/woc-panel，唯一对外入口）
│   ├── Dockerfile         # 前端 Vite 打包 + 后端 Fastify 网关（多架构）
│   ├── server/            # Fastify：cookie 鉴权 + 账号/实例/权限/生命周期 API + dockerode + 反代
│   └── web/               # React + TS + PWA（微信 PC 式布局，牛奶布艺 + 微信绿主题）
├── fnos/                  # 飞牛 fnOS 应用打包（.fpk 工程 + 构建说明）
├── scripts/
│   └── build-local.sh     # 本地构建面板+微信镜像（发布前自测 / 自托管自构建）
├── doc/                   # 文档与素材
│   ├── 技术方案.md         # 完整设计文档
│   ├── 运行原理.md         # 工作原理 + Docker 运行模式详解（新手向）
│   ├── 发布到GHCR.md       # 镜像发布到 GHCR 的两种方式
│   ├── 部署与运维.md       # 本文档：数据持久化 / 常见问题 / 密码找回 / 目录结构
│   └── img/               # logo 与界面截图
├── docker-compose.yml     # 单服务：panel（挂 docker.sock，按需创建实例）
├── .env.example           # 可选配置（账号密码、镜像版本、PUID/PGID、端口、时区）
└── README.md
```

数据：面板账号（含密码哈希）在 `./data-panel`，各微信实例在 docker 命名卷 `woc-data-<id>`；`./data-panel` 已在 `.gitignore` 中。
