Skip to content

errorpower/wechatoncloud-f1

 
 

Repository files navigation

WechatOnCloud

在飞牛 NAS(x86_64 / arm64)上运行服务端微信:可管理多个微信实例,每个实例是一个独立的微信会话;多个 web 用户通过浏览器访问被授权的实例,实现跨设备消息同步、多端共享。

设计与选型详见 技术方案.md。 部署形态:拉取 GHCR 预构建多架构镜像(或本地自构建),面板按需动态创建微信实例容器。不熟悉 Docker?直接看 Docker 运行模式详解


工作原理(一句话)

每个微信实例 = 一个容器,里面跑 Xvfb 虚拟显示 + 官方原版微信,KasmVNC 把画面串到浏览器。同一实例被多个浏览器连 = 共享同一个微信会话。不修改微信客户端

前面一层自研 面板(panel) 是唯一对外入口:负责账号登录、子账号与实例权限管理,经 docker 引擎按需创建/销毁微信实例容器,并反向代理到对应实例——浏览器只和面板打交道,KasmVNC 的凭据由面板在服务端注入,不下发前端。

浏览器 ──▶ panel(:36080) ──┬─ /               面板 SPA(登录 / 实例网格 / 子账号 / 进入桌面)
            cookie 鉴权     ├─ /api/*           账号、实例、权限接口
                           └─ /desktop/:id/*   反代 → 对应实例 KasmVNC(注入 Basic 鉴权)

panel ──(docker.sock)──▶ docker 引擎 ──▶ 按需创建/销毁微信实例容器 woc-wx-<id>
                                          每个实例 = 独立容器 + 独立数据卷 + 独立微信会话
                                          实例只在 docker 网络内暴露,不直连宿主

Docker 运行模式详解(新手向)

如果你对 Docker 不熟,这一节把本项目「怎么跑起来的」讲透。读完你就能看懂上面的图。

0. 先认识 5 个 Docker 概念

概念 一句话理解 在本项目里是什么
镜像 Image 只读的「软件安装包」,里面装好了程序和依赖 woc-panel(面板)、wechat-on-cloud(微信实例)
容器 Container 镜像「运行起来」的实例,相当于「正在跑的程序」。一个镜像能跑出多个容器 woc-panel 容器、多个 woc-wx-<id> 容器
卷 Volume 容器之外的持久磁盘。容器删了,卷里的数据还在 每个微信实例一个卷 woc-data-<id>,存登录态和消息
网络 Network 容器之间互通的「虚拟局域网」,容器之间可用容器名当域名互访 面板和所有实例在同一网络里,面板用 http://woc-wx-<id>:3000 找实例
docker.sock Docker 引擎的「遥控器」(宿主上的一个特殊文件 /var/run/docker.sock)。谁拿到它,谁就能指挥 Docker 创建/删除容器 挂进面板容器,面板才能「动态造微信实例」

Compose 则是「用一个 docker-compose.yml 文件描述要跑哪些容器,docker compose up -d 一条命令拉起」。本项目的 compose 里只有面板一个服务

1. 本项目有两类容器(运行角色不同)

这是本项目最容易迷惑的地方:不是所有容器都写在 docker-compose.yml 里。

① 面板容器 ② 微信实例容器
容器名 woc-panel(固定一个) woc-wx-<随机id>(可有多个)
用哪个镜像 woc-panel wechat-on-cloud
谁来启动 执行 docker compose up -d 面板:你在网页点「新建微信实例」时,面板通过 docker.sock 自动 docker run
写在 compose 里吗 (运行期动态创建,compose 里看不到)
对外暴露端口 是,宿主 36080 → 容器 8080 否,只在 docker 网络内,由面板反代
数据存哪 宿主目录 ./data-panel 各自的命名卷 woc-data-<id>
生命周期 常驻 你在面板「删除实例」时销毁(默认保留卷)

一句话:你只手动管面板这一个容器;微信实例是面板帮你按需开关的。 这就是为什么面板要挂 docker.sock——它需要「遥控」Docker 去开关微信实例容器。

2. 镜像从哪来:两种「构建/获取」模式

容器要跑,先得有镜像。本项目的两个镜像有两条获取途径,任选其一快速开始对应方式 A / B):

方式 A · 本地自构建 方式 B · 拉取官方镜像
怎么做 ./scripts/build-local.sh(用本仓库 Dockerfile 在你机器上造镜像) docker compose up -d(自动从 GHCR 下载现成镜像)
适合谁 官方还没发布镜像时 / 想自己改代码 / 内网无法访问 GHCR 普通用户,开箱即用
前提 本机能拉到基础镜像(node、KasmVNC base) GHCR 上已发布且包为公开(见发布到 GHCR
产物 本地镜像,标签和 compose 里写的一模一样 同名镜像,来自云端

compose 的拉取策略是默认值(missing):本地已有同名镜像就直接用,没有才去 GHCR 拉。所以方式 A 构建完,docker compose up -d 会直接用你的本地镜像,不会再联网。想升级到 GHCR 最新版:docker compose pull && docker compose up -d

第三个「镜像」其实是微信本体:它不打进任何镜像,而是你在面板点「下载并安装」时,由实例容器实时从腾讯官方 CDN 下到自己的卷里(见数据持久化)。

3. 从零到能用,整体发生了什么

你: docker compose up -d
      └─▶ Docker 读取 docker-compose.yml
            └─▶ 拉起【面板容器 woc-panel】,挂上 ./data-panel 和 docker.sock,暴露 36080 端口

你: 浏览器开 http://NAS:36080 → 登录 → 点「新建微信实例」
      └─▶ 面板通过 docker.sock 指挥 Docker:
            ├─ docker run 一个【微信实例容器 woc-wx-xxx】
            ├─ 给它挂一个新卷 woc-data-xxx(存登录态/消息)
            └─ 接到同一个 docker 网络(面板才能反代到它)

你: 进入该实例 → 点「下载并安装」
      └─▶ 面板 docker exec 进实例容器,触发脚本从腾讯 CDN 下载微信、解压到卷

你: 点「进入电脑版微信」→ 手机扫码
      └─▶ 浏览器 ⇄ 面板(反代+注入鉴权) ⇄ 实例容器的 KasmVNC ⇄ 微信窗口

4. 常用命令速查

docker compose up -d            # 启动面板(首次会拉/用镜像)
docker compose down             # 停止并删除面板容器(不动数据卷和微信实例)
docker compose pull             # 把面板/微信镜像更新到 GHCR 最新
docker ps                       # 看正在运行的容器(能看到 woc-panel 和各 woc-wx-*)
docker logs -f woc-panel        # 看面板日志
docker logs -f woc-wx-<id>      # 看某个微信实例日志
docker volume ls | grep woc     # 看所有微信实例的数据卷

⚠️ 微信实例容器请始终在面板网页里增删,不要手动 docker rm 它们——否则面板的实例登记和真实容器会对不上。


快速开始

需已安装 Docker(含 Compose 插件)。x86_64 / arm64 均可。

docker-compose.yml 引用的是 GHCR 上的镜像 ghcr.io/gloridust/{woc-panel,wechat-on-cloud}这两个镜像需先存在——要么官方已发布(你能直接拉取),要么你在本地自行构建。二选一:

方式 A · 本地自构建(官方尚未发布镜像时用这个)

git clone https://github.com/Gloridust/WechatOnCloud.git WechatOnCloud
cd WechatOnCloud
cp .env.example .env            # 至少改掉默认密码 WOC_PASSWORD
./scripts/build-local.sh        # 构建面板 + 微信实例镜像,打成 compose 用的同名标签
docker compose up -d            # compose 默认优先用本地镜像,不会再去 GHCR

方式 B · 拉取官方镜像(已发布到 GHCR 后)

git clone https://github.com/Gloridust/WechatOnCloud.git WechatOnCloud
cd WechatOnCloud
cp .env.example .env            # 至少改掉默认密码 WOC_PASSWORD
docker compose up -d            # 直接从 GHCR 拉取

报错 error from registry: denied?说明 GHCR 上还没有该镜像(或包是私有的)。用方式 A 本地构建,或见下方「发布到 GHCR」

无论哪种方式,都会拉起面板容器 woc-panel(唯一对外服务)。浏览器访问 http://<NAS_IP>:36080

  1. .env 里设置的管理员账号(默认 admin / wechat)登录面板;
  2. 管理员在面板「实例」页点「新建微信实例」,命名并选择哪些子账号可访问 → 面板自动 docker run 起一个微信实例容器(微信镜像本地没有时才会从 GHCR 拉取);
  3. 进入该实例,点「下载并安装」微信(约 190~210MB,进度条实时显示,仅管理员可操作);
  4. 装好后点「进入电脑版微信」→ 浏览器里出现微信窗口,手机扫码登录即可。

之后被授权的用户换任意设备打开同一地址登录面板,看到自己有权访问的实例,进入即是同一个微信会话。

宿主只对外暴露面板的 36080 一个端口;微信实例容器仅在 docker 网络内、由面板反代,不直连宿主。要改端口/版本见 .env

面板能做什么

功能 谁可用 说明
新建 / 删除微信实例 管理员 一键创建独立微信会话容器;新建时勾选可访问的子账号。删除默认保留数据卷(聊天记录),可选彻底清除
实例权限分配 管理员 在实例上改「可访问账户」,或在账户上改「可访问实例」,双向管理
下载并安装 / 更新微信 管理员 对某实例一键下载官方微信 Linux 版到其数据卷、解压安装;带进度条;后续可一键「更新到最新版」
进入电脑版微信 被授权用户 在浏览器里操作对应实例的微信,扫码登录、收发消息
修改密码 所有人 改自己的登录密码
子账号管理 管理员 创建 / 禁用 / 重置 / 删除子账号,并分配实例访问权限
安装为 App 所有人 iOS Safari「添加到主屏幕」、桌面 Chrome「安装」当原生 App(PWA)

子账号是访问这套面板的身份,不是另开一个微信。管理员隐式拥有全部实例访问权;子账号只能看到被授权的实例。

微信本体不打进镜像,而是新建实例后在面板点「下载并安装」时下载到该实例的数据卷,所以镜像很小、构建快、不依赖腾讯 CDN。

架构自动适配

镜像本身多架构(amd64/arm64);下载微信时容器内运行时再自动检测 CPU 架构dpkg --print-architecture)取对应官方包:

运行机器 架构 自动下载
Intel/AMD NAS、x86 服务器 amd64 WeChatLinux_x86_64.deb
ARM NAS、Apple Silicon Mac arm64 WeChatLinux_arm64.deb

到飞牛上(无论 x64 还是 arm)docker compose up -d 同一条命令,无需改任何架构相关配置。

自定义配置(可选)

复制 .env.example.env 后按需修改,可配置项见 .env.example:管理员账号密码、镜像版本(WOC_VERSION,建议上线后钉到具体版本)、PUID/PGID、时区、端口。


发布到 GHCR

两种方式任选其一。

方式 A · GitHub Actions(推荐)

仓库自带 GitHub Actions(.github/workflows/release.yml),在你推送 vX.Y.Z 标签或发布 Release 时,自动构建多架构(amd64+arm64)镜像并推到 GHCR:

git tag v1.0.0
git push origin v1.0.0     # 触发 Actions,产出 ghcr.io/<owner>/woc-panel:1.0.0 等标签
# 或在 GitHub 上 Publish 一个 Release(会额外打 latest):
gh release create v1.0.0 --title v1.0.0 --notes "..."

注意:单纯 push tag 只产出 X.Y.Z / X.Y / X不会更新 latest;要更新 latest 请改用 发布 Release 或在 Actions 里手动 workflow_dispatch

方式 B · 本机 buildx 手动构建并推送(不走 Actions)

适合想立刻出包、或不依赖 CI 的场景。需要 Docker Buildx(Docker Desktop 自带;纯 Linux 跨架构需先装 QEMU:docker run --privileged --rm tonistiigi/binfmt --install all)。

# 1) 登录 GHCR(PAT 需 write:packages 权限)
echo <YOUR_GITHUB_PAT> | docker login ghcr.io -u <github 用户名> --password-stdin

# 2) 首次创建并启用多架构构建器(已建过改用 docker buildx use woc)
docker buildx create --name woc --use

# 3) 构建并推送两个镜像(amd64 + arm64)。VER 与 git tag 保持一致(不带 v)
VER=1.0.1
docker buildx build --platform linux/amd64,linux/arm64 \
  -t ghcr.io/gloridust/woc-panel:$VER -t ghcr.io/gloridust/woc-panel:latest \
  --push ./panel
docker buildx build --platform linux/amd64,linux/arm64 \
  -t ghcr.io/gloridust/wechat-on-cloud:$VER -t ghcr.io/gloridust/wechat-on-cloud:latest \
  --push ./docker

gloridust 换成你的 GHCR 命名空间(与 docker-compose.yml / WOC_IMAGE_PREFIX 一致)。 只想本机自用、不推 GHCR,用 ./scripts/build-local.sh 构建本机架构单架构镜像即可。

发布后:把包设为公开

首次发布后还需把 GHCR 包设为公开,否则别人 docker compose up -d 会报 denied

  1. 打开 GitHub → 你的头像 → Packages → 分别进入 woc-panelwechat-on-cloud
  2. Package settings → Change visibility → Public

若想保持私有,则使用者需先 docker login ghcr.io(用具备 read:packages 的 PAT)才能拉取。 在镜像发布之前,本地用 ./scripts/build-local.sh 自构建即可,无需等待发布。


数据持久化

  • 面板数据(用户、实例元信息、密码哈希):容器内 /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(创建/销毁实例所需),它等同宿主 root 权限。因此:

  • 绝不要把面板裸暴露公网:只在内网访问,或经飞牛远程访问 / VPN / 内网穿透;
  • 务必改掉默认密码(默认 admin / wechat):cp .env.example .env 后改 WOC_PASSWORD,或登录后在「修改密码」里改;
  • 实例的增删、微信安装/更新等触碰 docker 引擎的操作仅限管理员;docker API 绝不暴露给前端;
  • KasmVNC 凭据由面板服务端注入,浏览器永远拿不到;实例容器名由内部随机 ID 派生,避免注入;
  • 面板与外网之间再套一层 HTTPS 反代(飞牛自带反代 / Caddy / Nginx)获得正经 TLS;
  • 进一步加固(陌生设备验证码、审计日志、并发控制)见 技术方案.md 第 5 节。

中文输入

用你本地(客户端)的输入法打中文,容器内无需安装任何 IME。 镜像已默认开启 KasmVNC 的 「IME Input Mode」:拼音联想在你本机完成,只把成品汉字发进容器。直接在微信输入框打字即可。

  • 默认值只对未存过该设置的浏览器生效。之前手动开/关过的,浏览器 localStorage 值优先;想验证默认效果用无痕窗口。
  • 已知小毛病:超长拼音串未全部转成汉字就回车,偶尔丢字(issue #97),长句分段输入即可。
  • 兜底:Chrome/Edge 下本地 ⌘C → 远端 Ctrl+V 无缝粘贴;Firefox 用控制面板的 Clipboard 文本框中转。

常见问题

现象 排查
新建实例失败 多为面板拉不到微信镜像或连不上 docker.sock。确认 docker.sock 已挂载、宿主能访问 GHCR;看面板日志 docker logs woc-panel
界面/消息显示成方块 中文字体没装好,确认实例镜像含 fonts-noto-cjk
微信起不来 / 黑屏 看实例日志 docker logs woc-wx-<id>;确认 seccomp=unconfinedshm_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)。

重置超管密码(离线找回)

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

docker compose stop panel                 # 1) 先停面板,避免覆盖你的手动修改
  1. 编辑 ./data-panel/accounts.json,给对应用户对象加一行 "resetPassword": true
{
  "id": "...", "username": "admin", "role": "admin",
  "passwordHash": "...", "disabled": false,
  "resetPassword": true
}
docker compose up -d                       # 3) 启动,面板初始化时会重置该账号

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

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


目录结构

WechatOnCloud/
├── .github/workflows/
│   └── release.yml        # 打 tag / 发 Release 时构建多架构镜像并推送 GHCR
├── docker/                # 微信实例镜像(ghcr.io/<owner>/wechat-on-cloud)
│   ├── Dockerfile         # KasmVNC base + 中文字体 + 微信运行时依赖 + 默认开 IME(不打包微信本体)
│   ├── wechat-ctl.sh      # 运行时下载/解压/更新微信(面板经 docker exec 触发,状态写 /config/.woc-state)
│   └── autostart          # openbox 会话启动:等待微信就绪 + 常驻拉起(含崩溃自重启)
├── panel/                 # 自研面板(ghcr.io/<owner>/woc-panel,唯一对外入口)
│   ├── Dockerfile         # 前端 Vite 打包 + 后端 Fastify 网关(多架构)
│   ├── server/            # Fastify:cookie 鉴权 + 账号/实例/权限 API + dockerode 管理实例 + 反代
│   └── web/               # React + TS + PWA(牛奶布艺 + 微信绿主题)
├── fnos/                  # 飞牛 fnOS 应用打包(.fpk 工程 + 构建说明)
├── scripts/
│   └── build-local.sh     # 本地构建面板+微信镜像(发布前自测 / 自托管自构建)
├── docker-compose.yml     # 单服务:panel(挂 docker.sock,按需创建实例)
├── .env.example           # 可选配置(账号密码、镜像版本、PUID/PGID、端口、时区)
├── 技术方案.md            # 完整设计文档
└── README.md

数据:面板账号(含密码哈希)在 ./data-panel,各微信实例在 docker 命名卷 woc-data-<id>./data-panel 已在 .gitignore 中。


路线图

  • MVP:Docker + 微信原生版 + KasmVNC,浏览器扫码登录、收发消息
  • 自研面板:cookie 鉴权 + 反代 + 子账号管理 + PWA(KasmVNC 凭据不下发前端)
  • 微信本体运行时下载到数据卷:面板一键「下载并安装 / 更新」,带进度条
  • 多实例管理 + 按账号的实例访问权限(RBAC)
  • 预构建多架构镜像发布到 GHCR + GitHub Actions 自动化
  • 面板外层 TLS / 陌生设备验证码 / 审计日志
  • 多端并发控制(操作控制权心跳软锁 + 只读遮罩 + 申请接管)
  • 掉登录时 web 端二维码重扫入口
  • [~] 打包成飞牛原生 fpk 分发(工程已就绪见 fnos/,待真实设备验证 docker.sock 权限)

About

云微WOC,云微信,自由连接

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • TypeScript 70.1%
  • CSS 19.4%
  • Shell 5.0%
  • JavaScript 2.6%
  • Dockerfile 2.5%
  • HTML 0.4%