【软件杂谈】基于应用层协议(WebSocket)重构 Minecraft 群组服网关

发布于: 2026-01-14 15:19:55 📖 37 次阅读

引言:多模组群组服服主的终极噩梦

作为一个经营着多版本、多模组(Mod)服务器群组的服主,我长期以来都被一个架构问题所困扰:如何在保证兼容性的前提下,实现统一入口?

我的服务器群组非常复杂:既有 1.7.10 的GTNH,也有 1.12.2 的主线周目,更少不了1.18.2的机械动力服务器,还有 1.20.1 的原版生存服。我想将服务器使用单一IP做统一管理,传统的解决方案是使用 Velocity 搭建一个适配模组服的群组网络。

但这种方案对于“重度模组服”来说简直是灾难:

  1. 大厅的兼容性地狱:你需要一个兼容多版本的“大厅服”作为中转站。但是,一个挂载了 200 个 Mod 的客户端,往往无法连接到一个纯净的大厅(会发生各种兼容性问题)。
  2. 强制的二次跳转:玩家必须先连上大厅,再跨服。这不仅增加了连接耗时,还容易在跨服时的握手阶段发生崩溃。
  3. 多 IP 的无奈:最终,我不得不给每个子服分配不同的端口甚至 IP,让玩家自己在客户端里手动添加。这完全破坏了“一个服务器群组”的整体感。

我也曾尝试自行开发反向代理,但 Minecraft 原生协议(TCP) 在握手阶段提供的信息太少了——它几乎只有目标地址和协议版本,代理服务器根本无法知道玩家到底想去哪个子服。

直到最近,我注意到Minecraft WebSocket 握手技术 出现,为这个问题带来了降维打击般的解决方案。


核心灵感:从 TCP 到应用层的降维打击

传统的 Minecraft 连接是纯 TCP 的。当我们连接服务器时,如同在一个黑盒子里握手,代理服务器只能看到“有人来了”,却不知道“他是谁”。

WebSocket 的引入改变了一切。WebSocket 在建立连接之前,必须先进行一次 HTTP Upgrade 握手
这意味着什么?意味着我们可以在握手阶段使用 HTTP 协议 的所有特性,其中最强大的就是——自定义 Request Headers(请求头)

我的构想是:彻底抛弃 BungeeCord 等应用层代理,改用 Nginx 甚至云原生网关,通过识别 HTTP 请求头中的自定义标签,实现流量的自动路由。

在这个新架构中,不再有“大厅服务器”的概念,也没有复杂的 BungeeCord 配置文件。整个流程如下:

1. 客户端侧 (Client)

我们需要在每个整合包中预装支持 WebSocket 的模组(Mod)。
关键在于配置:我们修改该 Mod 的配置文件,为不同整合包的客户端注入唯一的身份标识。

  • 科技服客户端:配置发送 Header X-Target-Server: tech-1.7.10
  • 魔法服客户端:配置发送 Header X-Target-Server: magic-1.12.2

2. 网关侧 (The Gateway)

这是整个架构的大脑。我们不再运行 Java 版的代理端,而是运行一个高性能的 Web 反向代理(如 Nginx, Traefik 或 Go 自研网关)。
网关只做一件事:检查 HTTP 握手包里的 X-Target-Server 头,然后把连接像管道一样接到对应的后端端口。

3. 服务端侧 (Server)

后端 Minecraft 服务器安装对应的 WebSocket 接收模组,监听本地端口,等待来自网关的流量。


技术实现细节

步骤一:客户端配置 (伪代码)

假设我们使用的 WebSocket 模组允许自定义 HTTP 头(这在技术上非常容易实现),我们在 1.7.10 科技服整合包的 config/ws_client.json 中写入:

{
  "connection_type": "websocket",
  "gateway_url": "ws://play.myserver.com",
  "custom_headers": {
    "X-Target-Server": "tech-modpack",
    "X-Client-Version": "1.7.10-v3"
  }
}

步骤二:Nginx 网关配置

这是最精彩的部分。我们利用 Nginx 的 map 指令和反向代理功能,无需编写复杂的 Java 插件代码,仅用十几行配置就完成了路由分发:

http {
    # 定义 WebSocket 升级映射
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    # 核心逻辑:根据 Header 决定去哪里
    # 如果 Header 是 tech-modpack,转发到 20001
    # 如果 Header 是 magic-modpack,转发到 20002
    map $http_x_target_server $backend_port {
        default       25565; # 默认落点(或者是错误页)
        "tech-modpack"  20001;
        "magic-modpack" 20002;
    }

    server {
        listen 80; # 或者 443 (SSL)
        server_name play.myserver.com;

        location / {
            # 使用变量动态转发
            proxy_pass http://127.0.0.1:$backend_port;

            # WebSocket 必须的握手头
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;

            # 传递真实 IP
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

这个方案的巨大优势

  1. 完美的单 IP 体验
    无论玩家玩的是哪个版本的整合包,他们只需要输入 play.myserver.com。网关会根据“暗号”(Header)自动把他们送到正确的地方。
  2. 彻底消灭“进服崩溃”
    玩家实际上是直连子服务器的。不存在“先连大厅再跨服”的过程,也就彻底根除了 Mod 列表不匹配导致的跨服崩溃问题。
  3. 版本完全隔离
    Nginx 根本不在乎你传的是 Minecraft 1.20 的包还是 1.7.10 的包,它只负责转发数据流。这意味着你的群组里可以同时存在任何版本的服务器,互不干扰。
  4. CDN 与安全防护
    既然走了 WebSocket (HTTP/80端口),我们甚至可以将服务器套在 Cloudflare 等 CDN 后面!这不仅能隐藏源站 IP,还能利用 Web 级的 WAF 防火墙来抵御 DDoS 攻击,这是传统 TCP 协议难以做到的。

结语

长久以来,Minecraft 模组服的开服门槛都受限于糟糕的网络架构。通过引入 WebSocket 并利用应用层协议(Layer 7)的特性,我们实际上是把 Minecraft 的流量伪装成了普通的 Web 流量。

这不仅仅是一个技术上的 trick,它可能代表了未来群组服务器架构的新方向:轻量化、Web 化、去中心化。

目前的方案还在实验阶段,但我相信,随着 WebSocket 模组的完善,这种基于 Header 的智能路由网关,终将成为多模组群组服的标配。