随笔:我在飞牛 NAS 上跑了两周的一个开源棋类应用(含 Docker 部署与两个踩坑记录)

关键词:Docker、自托管、Node.js、NAS 部署、AI 对战、飞牛 fnOS

起因:工作间隙想下两步棋,但不想装 App

工作间隙想下两步棋,但不想装 App、不想注册、不想在公共平台等匹配。方案是:在自己的 NAS(飞牛 fnOS)上跑一个纯网页的三合一棋类服务,局域网内任何设备打开浏览器就能玩,数据全部留在本地。

选择的项目是 moyu-qile(摸鱼棋乐),纯 Node.js 自研、零外部依赖、MIT 开源,同时包含象棋、五子棋、军棋(翻棋)三个游戏,并内置 AI 对战、AI 教练、走法点评等能力。

一、部署步骤(4 条命令)

SSH 登录飞牛:

git clone https://github.com/personal82555/moyu-qile.git
cd moyu-qile

docker build -t moyu-qile:latest .

docker run -d --name moyu-qile --restart unless-stopped \
  -p 7025:7025 \
  -v "$PWD/data:/app/data" \
  moyu-qile:latest

curl -I http://127.0.0.1:7025

然后浏览器打开 http://<NAS内网IP>:7025,手机连同一 Wi-Fi 同样地址即可访问。

部署完成后的首页

三个部署注意点:

  1. -v "$PWD/data:/app/data" 不能省——存档(*-saves.json)、战绩(*-ranks.json)、路径配置都在这个卷里,不挂卷重建容器就全丢
  2. 端口冲突改 -p 7026:7025 即可
  3. 不想用 Docker 也可以 npm install && node server.js 直接跑(需要 Node 20+)

资源占用实测:

容器 CPU: 0.01%
容器内存: 8.7 MiB
端口: 7025->7025

对 NAS 来说基本可以忽略不计。

二、架构要点(值得借鉴的几个设计)

1. 前后端共用一套 JS

棋类规则引擎(chess.js / gomoku.js / junqi.js)在浏览器里跑,也在 Node 服务端跑(双人同屏、存档校验用同一份逻辑),不需要重复实现规则。

2. AI 能力分”本地引擎”和”大模型”两层

能力 实现 是否需要大模型
AI 对战(三档难度) α-β 剪枝 / 攻防评分 否
走法点评(这步亏多少分) 本机引擎算分对比 否
AI 教练 / 赛后复盘 OpenAI 兼容接口 是
AI 出残局 大模型生成 + 本地穷举校验 是(校验是本地的)

其中「AI 出题必须先过本地校验」这个设计我觉得最值得抄:象棋局面必须穷举出”确实存在一步将死”,五子棋必须确实”一步成五”,验不过就自动回退到内置题库——大模型的输出永远不能直接信。

走法点评

3. 模型接入的工程细节

  • KEY 输入框默认 type="password",点击才显示
  • 内置 测试连接 按钮,把失败原因分类成:KEY 失效(401)/ 模型名错误(404)/ 地址不可达(ECONNREFUSED)
  • 模型返回纯英文时,客户端自动补一句”必须用简体中文”重问一次
  • 局面描述给模型时用全中文坐标(”左起第2列、从红方底线往上第3行”),避免模型输出 b8 这类用户看不懂的字母
  • 🔒 隐私安心点:模型 KEY 只保存在浏览器 localStorage,不上传、不写入服务器,面板里有绿色提示写明这一点

模型设置

三、数据安全与自动化

  • 存档/战绩全部落在 /app/data 卷内,每 5 分钟自动存档,切后台、关页面还会立即再存一次
  • 支持存档路径在界面里自定义(换目录自动迁移)
  • 局中刷新会自动快照,下次进入询问”是否继续上一局”

对局未结束时点击其它页面、刷新、关闭标签都会先弹确认,避免误操作丢局——这个 beforeunload + 捕获阶段 click 拦截的做法很值得复用。

四、踩过的坑(附修复思路)

坑 1:象棋初始摆法写错

原实现把 8 个后排棋子循环放到了 c0..c7,结果每方只有 15 子、底线缺一个士、最右侧车的角位空着。修复方式是把 8 个子显式映射到 [0,1,2,3,5,6,7,8],中路单独放将/帅。

const back = ['车','马','相','士','士','相','马','车'];
[0,1,2,3,5,6,7,8].forEach((c, i) => {
  B[0][c] = { t: back[i], s: 'b' };
  B[9][c] = { t: back[i], s: 'r' };
});

验证标准:每方 16 子、开局 allLegal() 恰好 44 步、初始局面评估对称为 0。

坑 2:局面点评与 AI 回手的竞态

点评用 setTimeout(..., 40) 而 AI 回手用 60ms,理论上点评先跑,但一旦点评内部的搜索耗时超过 20ms,就可能出现”在 AI 走完之后才评估”的局面,导致结论完全相反。修复方式:点评改为 setTimeout(..., 0)(JS 单线程,先起跑的一定会先算完),并在快照里记录手数,评估前断言手数匹配。

五、小结

自托管的价值不在于”省了多少钱”,而在于规则由你定:数据不出内网、功能可随意改、AI 接口可随时换。

如果你也有一台吃灰的 NAS,这四个命令的成本非常低:

📦 新进展:已打包飞牛应用商店安装包(.fpk,真机安装/启停/卸载全流程验证通过),即将上架应用中心——到时在应用中心搜索「摸鱼棋乐」一键安装,无需命令。当前最快方式:

最快方式:不用克隆源码,直接拉公开镜像(GitHub Actions 自动构建更新):

docker pull ghcr.io/personal82555/moyu-qile:latest

docker run -d --name moyu-qile --restart unless-stopped \
  -p 7025:7025 -v "$PWD/data:/app/data" \
  ghcr.io/personal82555/moyu-qile:latest

也可以从源码构建:

git clone https://github.com/personal82555/moyu-qile.git
cd moyu-qile && docker build -t moyu-qile:latest .
docker run -d --name moyu-qile --restart unless-stopped \
  -p 7025:7025 -v "$PWD/data:/app/data" moyu-qile:latest

项目地址:github.com/personal82555/moyu-qile,欢迎 star。


📂 更多推荐

  • 查看更多相关文章:https://www.88531.cn
  • 关注公众号「实用软技」获取更多软件推荐和实用技巧
  • 所有软件均提供夸克网盘下载,公众号回复「软件」一键获取
100T高转存免费网盘资源精选【持续更中~~~~】:点击查看

发表回复