随笔:我在飞牛 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 同样地址即可访问。

三个部署注意点:
-v "$PWD/data:/app/data"不能省——存档(*-saves.json)、战绩(*-ranks.json)、路径配置都在这个卷里,不挂卷重建容器就全丢- 端口冲突改
-p 7026:7025即可 - 不想用 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
- 关注公众号「实用软技」获取更多软件推荐和实用技巧
- 所有软件均提供夸克网盘下载,公众号回复「软件」一键获取
