Files
WechatOnCloud/doc/部署与运维.md
Gloridust f3b3219cdb feat: 公网访问加固(登录限速/会话滑动续期)+ 管理页三 Tab 信息架构重构
公网/NAS 稳定性专项扫描的产出:

① 登录限速:面板常被直接暴露公网,/api/auth/login 原先无任何限速可被无限爆破。
双键计数(IP+用户名 5 次、IP 20 次 / 15 分钟窗口),触发回 429 + 面板日志告警;
用 socket 直连地址而非可伪造的 XFF;成功登录清零。已实测:5×401 → 第 6 次 429。

② 会话滑动续期:固定 30 天硬过期在"常年挂着"的 NAS 场景表现为"隔三差五要重登"。
现剩余不足一半自动续满(服务端),鉴权层顺手刷新 cookie maxAge(浏览器侧同步)——
活跃用户永不掉线,闲置超时才需重登。

③ DNS-rebind 钩子补 return reply(async 钩子已 send 后的规范终止写法)。

④ 运维文档新增「公网访问 / 反代部署」章节:nginx 完整示例(ws 升级头 +
proxy_read_timeout 3600s——默认 60s 是"桌面挂着不动 1 分钟就断线"的元凶 +
client_max_body_size)、Caddy/frp/Cloudflare 注意事项、PANEL_ALLOWED_HOSTS 提醒。

⑤ 管理页重构:7 个区块一条长滚动 → 「实例 / 用户 / 系统」三 Tab
(实例=日常操作;用户=子账号+本账号;系统=残留容器+数据卷+诊断日志+关于)。
牛奶布艺分段选择器(凹槽+浮起胶囊),Tab 角标点提示待处理事项(可升级/有残留),
记住上次停留 Tab;子账号(非管理员)视图不变。
2026-07-08 02:57:10 +08:00

139 lines
8.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 部署与运维
> 返回 [← 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/ # Fastifycookie 鉴权 + 账号/实例/权限/生命周期 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` 中。
## 公网访问 / 反代部署nginx 示例)
把面板暴露到公网(域名 + HTTPS有三件事必须做对否则表现为「登录 400 / 桌面黑屏 / 挂一会儿就断线」:
1. **把对外域名加进 `PANEL_ALLOWED_HOSTS`**`.env`,逗号分隔,支持 `*.example.com`),然后 `docker compose up -d` 重建(不是 restart。这是防 DNS-rebinding 的白名单,不加会被面板以 400 拒绝。
2. **反代必须透传 WebSocket**(远程桌面全靠它)。
3. **把空闲超时调大**。nginx 默认 `proxy_read_timeout 60s`——桌面静止不动 1 分钟没有数据流过nginx 就掐断连接,表现为「挂着不动就断线重连」。
```nginx
server {
listen 443 ssl;
server_name woc.example.com;
# ssl_certificate / ssl_certificate_key ...
location / {
proxy_pass http://<NAS 内网 IP>:36080;
proxy_http_version 1.1;
# WebSocket 升级(远程桌面/音频都走 ws
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 透传真实 Host与 PANEL_ALLOWED_HOSTS 对得上)
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 关键:空闲超时调大,否则桌面静止 60s 即断nginx 默认值)
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
# 大文件上传(传文件到桌面 / 卷导入)
client_max_body_size 3g;
}
}
```
其它反代同理Caddy 默认无空闲超时开箱即用frp 建议 `transport.heartbeatInterval` 保持默认并确认 `proxy_read_timeout` 类配置未收紧Cloudflare 免费版对 WebSocket 空闲约 100s 断开,桌面场景建议用「灰云」(仅 DNS或自建隧道。
安全提示面板已内建登录限速15 分钟窗口内同源失败 5 次即暂时锁定),但公网暴露仍建议:强密码、改默认端口、优先用 VPN/内网穿透而非直接开放。