# 泡泡堂 H5 复刻版 NAS Docker 部署 从构建失败到房间与对局实测
这篇文章记录我在绿联 DXP6800 Pro 上部署泡泡堂风格 H5 复刻版的过程。目标不是复刻官方服务端,而是在家庭局域网里运行一个浏览器多人游戏,验证建房、角色选择、机器人补位和实时对局。
《泡泡堂》由 Nexon 开发。游戏名称、角色、地图、图片、音效、商标及其他相关权利归 Nexon、盛趣游戏等各自权利人所有,具体权属以官方页面和权利登记信息为准。文中截图仅围绕部署和测试结果作少量说明性引用。
本文仅供学习和个人测试。社区项目 tpoisonooo/BnB 未给出明确的整体许可证,README 也写明素材仅用于学习研究。仓库公开可见不等于允许转载、修改或再分发;缺少许可证通常意味着不能据此推定获得这些权利。代码仓库、游戏名称、角色、地图、图片和音效的权利归各自权利人所有。
本文只记录部署方法,不提供源码压缩包、游戏客户端、运行数据或额外下载渠道,也不建议公开收费运营。文中截图仅用于说明部署和测试结果。
部署范围与实测结果
项目标识:
tpoisonooo/BnB
本文只标注项目名称用于来源说明,不提供源码压缩包或下载直链。需要核对来源时,请从作者公开页面进入,并先阅读当前 README 和使用边界。
本次测试环境如下。
| 项目 | 实测信息 |
|---|---|
| NAS | 绿联 DXP6800 Pro |
| 部署目录 | /volume1/docker/bnb |
| 容器运行时 | Docker Compose |
| 基础镜像 | node:24-alpine |
| NAS 端口 | 47821 |
| 容器端口 | 3001 |
| 健康检查 | /healthz |
服务启动后,容器状态为 Up (healthy),健康检查返回 ok。首页可以打开,房间可以创建,角色可以选择,Bot 可以补位,完整对局能够运行。
这套项目不连接盛大原版客户端。它是独立的 H5 复刻版,浏览器页面和 WebSocket 房间服务由同一个 Node.js 进程提供。
运行架构
整个部署只有一个容器,数据路径也比较直接:
浏览器
|
| HTTP 静态资源
| WebSocket 房间与游戏消息
v
NAS TCP 47821
|
v
容器内 Node.js 3001
|
+-- client/ 页面与素材
+-- server/ 房间、游戏和 Bot 逻辑项目使用 ws 处理 WebSocket。玩家建房、加入、准备、开局和游戏输入都走同一条连接。服务端没有数据库,房间状态保存在内存中,所以容器重启后房间会清空。
这个结构适合轻量局域网使用,也意味着它没有账号体系、持久化战绩、权限管理和成熟的公网运营能力。
准备目录和源码
先在 NAS 的 Docker 共享目录中建立独立目录:
/volume1/docker/bnb从项目 GitHub 页面下载 ZIP 并解压,最终目录中应该能看到:
bnb/
├── Dockerfile
├── compose.yaml
├── package.json
├── package-lock.json
├── client/
└── server/不要在 NAS 的 Docker 搜索结果里随便找同名镜像。当前项目没有官方镜像;即使自行构建,也只应使用能够核对来源且已确认使用范围的文件。
Dockerfile
本次使用的 Dockerfile 如下:
FROM node:24-alpine
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3001
COPY --chown=node:node package.json package-lock.json ./
RUN npm ci --omit=dev --ignore-scripts
COPY --chown=node:node server ./server
COPY --chown=node:node client ./client
USER node
EXPOSE 3001
CMD ["node", "server/index.js"]这里有两个关键点。
第一,package.json 和 package-lock.json 必须在复制阶段交给 node 用户。否则从部分 NAS 共享目录复制文件时,ACL 权限可能一起进入镜像,运行时出现 permission denied。
第二,容器最后切换到普通用户 node,不使用 root 运行应用。项目运行期间只需要读取源码,不需要写业务目录。
Compose 配置
NAS 对外开放 47821,容器内部保持 3001:
services:
bnb:
build:
context: .
image: bnb-web:local
container_name: bnb-web
init: true
restart: unless-stopped
environment:
TZ: Asia/Shanghai
PORT: "3001"
ports:
- "47821:3001"
read_only: true
tmpfs:
- /tmp:size=16m
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
healthcheck:
test:
- CMD
- node
- -e
- "fetch('http://127.0.0.1:3001/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
interval: 30s
timeout: 5s
retries: 3
start_period: 15s根文件系统设为只读,应用需要的临时目录单独挂载到内存。cap_drop: ALL 和 no-new-privileges:true 降低容器获得额外系统权限的机会。
启动命令:
cd /volume1/docker/bnb
docker compose up -d --build当前 Compose 使用自定义的单端口映射,不依赖数据库,也不需要额外挂载业务数据卷。
第一次启动遇到的权限错误
第一次构建成功后,容器立即进入重启状态:
Restarting (1)访问 47821 没有响应。容器日志给出了根因:
Error: Cannot read package config /app/package.json: permission denied.
code: 'ERR_INVALID_PACKAGE_CONFIG'这说明镜像已经构建完成,Node 进程也在运行,只是普通用户 node 无法读取 /app/package.json。
最初的 Dockerfile 只给 server 和 client 使用了 COPY --chown=node:node,遗漏了两个 JSON 文件。修复方式是只改这一处:
COPY --chown=node:node package.json package-lock.json ./重新构建并重建容器:
docker compose up -d --build --force-recreate如果只看 Docker 的“已启动”提示,很容易误以为应用正常。先检查健康状态,再看日志,能更快区分“容器运行”和“业务可用”。
启动验收
检查容器:
docker compose ps正常状态应包含:
Up (healthy)
0.0.0.0:47821->3001/tcp检查健康接口:
curl -fsS http://127.0.0.1:47821/healthz返回:
ok检查端口:
ss -ltnp | grep ':47821'健康接口通过,只说明 Node HTTP 服务已经可以响应。再打开浏览器,才能验证页面资源和 WebSocket 是否都正常。
浏览器进入游戏
访问:
http://NAS局域网IP:47821首页不要求注册账号。输入昵称后进入大厅,可以创建或加入房间。房间提供六个位置,玩家可以切换宝宝和小海盗,空位在游戏开始后由 Bot 补齐。

页面的 WebSocket 地址直接取自当前浏览器地址。通过 HTTP 打开时使用 ws://,通过 HTTPS 反向代理打开时使用 wss://,前端不需要额外改配置。
多人联机验证
建议至少准备两个独立浏览器窗口、两台电脑,或者一台电脑加一部手机。每个客户端使用不同昵称,依次完成建房、大厅加入、选择角色、准备和开局,再检查双方移动、放泡泡、聊天和开局状态是否同步。

机器人补位适合单人先测试地图和操作,但它不能代替真人联机测试。实际邀请朋友前,应按上面的步骤把两个客户端的进出房和对局流程完整走一遍。
日常运维
查看状态和日志:
cd /volume1/docker/bnb
docker compose ps
docker compose logs --tail=100 bnb重启服务:
docker compose restart bnb停止服务:
docker compose down项目不需要数据库备份。需要备份的只有配置文件、Dockerfile 和后续自己对源码的修改。房间数据存在内存里,重启后不会恢复。
外网访问与安全边界
这套应用默认没有账号认证、访问控制、房间密码和公网限流。直接开放 47821 会让任何知道地址的人都能进入大厅,也会让未经审核的 WebSocket 连接直接落到 NAS 上。
只在局域网或 Tailscale 等私有网络中使用,风险最低。需要绑定域名时,应使用带 HTTPS 的反向代理,并正确转发 WebSocket Upgrade。即使加了 HTTPS,也不要把“能打开网页”误认为“已经具备公开运营能力”。
如果上游项目后续加入账号、持久化房间和权限系统,仍应重新检查数据库、备份、限流和隐私策略。这次部署的是一套轻量复刻版,不是完整的游戏服务平台。
总结
这次部署最终只用了 NAS 上的一个目录、一个 Node.js 容器和一个对外端口。构建过程简单,最容易出错的环节反而是 NAS 共享目录权限进入镜像后导致的文件读取失败。
项目的优势是启动轻、无需数据库、浏览器直接加入,适合家庭局域网临时开局。限制也很明确:没有持久化账号、没有管理后台,项目许可和游戏素材授权都需要单独核对。
如果只是想在 NAS 上验证一套轻量多人网页游戏的部署方式,这个项目已经足够完整。若要公开运营,应换用具有清晰许可、完整安全能力和明确素材授权的方案。
本文记录个人学习和局域网测试,不提供源码压缩包、游戏资源包、客户端文件、账号凭据或额外分发渠道。该项目不是官方服务端;项目名称、代码及各游戏素材的权利归各自权利人所有。未经许可,请勿公开收费运营、重新打包源码、转存或分发游戏素材。


