泡泡堂 H5 复刻版 NAS Docker 部署:从构建失败到房间与对局实测

阅读 -- 次

# 泡泡堂 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://,前端不需要额外改配置。

多人联机验证

建议至少准备两个独立浏览器窗口、两台电脑,或者一台电脑加一部手机。每个客户端使用不同昵称,依次完成建房、大厅加入、选择角色、准备和开局,再检查双方移动、放泡泡、聊天和开局状态是否同步。

浏览器中的对局、Bot 补位与右侧状态面板
浏览器中的对局、Bot 补位与右侧状态面板

机器人补位适合单人先测试地图和操作,但它不能代替真人联机测试。实际邀请朋友前,应按上面的步骤把两个客户端的进出房和对局流程完整走一遍。

日常运维

查看状态和日志:

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 上验证一套轻量多人网页游戏的部署方式,这个项目已经足够完整。若要公开运营,应换用具有清晰许可、完整安全能力和明确素材授权的方案。

本文记录个人学习和局域网测试,不提供源码压缩包、游戏资源包、客户端文件、账号凭据或额外分发渠道。该项目不是官方服务端;项目名称、代码及各游戏素材的权利归各自权利人所有。未经许可,请勿公开收费运营、重新打包源码、转存或分发游戏素材。
消息盒子

# 暂无消息 #

只显示最新10条未读和已读信息

版权与侵权投诉