自建云游戏服务器的一些可行性研究

2026 年 01 月 04 日

想要做的事情进展缓慢。大神级别项目的代码太复杂,看几行代码就能让我睡一天,而且最后搞不定的可能性也很大……所以这几天干脆暂时转移一下视线,玩玩游戏,算是放松一下。

之前简单的玩过云游戏,当时用的方法很简单:给电脑装一个服务端(sunshine),给 Switch 和电视盒上装个客户端(moonlight),配好连接就能开玩。

最近因为配置好了 NAS,突然想到,反正是 24 小时开机,是不是可以直接用 NAS 来当云游戏服务器?

做了两天实验,至于结果……虽然确实成功了,但由于我的 NAS 性能太差,效果难以让我满意,因此可能不会进一步折腾了,等未来有了更好的硬件再说。

所以这篇文章只是记录一下可行性研究,而不是一篇 step by step 的教程。需要提前说明的是,整个部署过程比较复杂,文章不涉及太多琐碎细节,对于没有相关基础知识的读者不会太友好。我自己也是在学习中,所以读者如果不是有执念的话就不要勉强自己了。

一些基础概念梳理

不难理解,游戏的本质是一个不断画图的程序,从外设接收输入,然后每秒要输出几十至上百帧图片。

而云游戏的本质,就是让游戏在服务器上运行,从客户端接收输入,然后把输出的图片帧送到客户端。

很容易看出,想玩的开心,需要以下几个要件:

  • 为了更快的输出图片,需要高性能的服务器,也就是要求 CPU/GPU 的性能足够。
  • 为了更及时的传输,需要高速的网络。
  • 游戏的类型也有影响,动作类游戏对输入到画面更新的时间有着严格要求,文字类游戏有一点延迟倒是问题不大。

其他的要素影响相对小很多,比如连续图片实际是作为视频传输的,因此编码方式对传输速度可能有轻微的影响,但同时对设备的编码/解码能力又提出了不同的要求。所以最终效果是需要根据硬件能力来权衡(trade-off)的。

有头(headful)与无头(headless)的区别

对于真正运行游戏的服务器,可以有显示器(headful),也可以没有显示器(headless)。

如果是 headful,那问题相对简单。sunshine 这种服务端可以通过录屏来输出,但只有一个屏幕,意味着同一时刻只能有一个人在用。如果不想接显示器的话,就需要显卡欺骗器这种插头。

如果是 headless,那就完全不用显示器,同时功能也可能更强大。因为显示器是虚拟的,可以根据客户端的配置来动态生成或调节。有的服务端允许多个客户同时连接,也就是可以虚拟多个显示器。但配置起来可能需要很多调试的精力。

服务器软硬件方案选择

目前看来,服务器还是只能选 x86/64,没法选 arm。显卡的话只能是常见的 AMD/Intel/Nvidia。这个限制不仅来自于 sunshine 这个几乎是必备的流服务软件,目标游戏本身所需的运行环境也是需要考虑的要素。

操作系统的影响现在似乎相对小一些了。具体说来,Windows 游戏可以通过兼容层跑在 Linux 上,因此服务器用 Linux 就可以。

所以,结合上面提到的 headful/headless 选择问题,如果目标包含 Windows 游戏的话(基本不可能不包含吧),那么考虑以下几个选择:

  • headful: windows + sunshine
  • headless: linux + docker,其中 docker 可以用以下方案:
    • steam-headless。
    • games-on-whales 的 wolf。
    • 其他目前还在进化的方案,比如 umu-launcher,但实际上这个跟前两个其实不是一个层级。

我尝试了 steam-headless 和 wolf。前者失败了,后者最终成功。umu-launcher 理论上是可以整合在 wolf 里面的,但要花更多精力,因此简单尝试失败后未进一步深入。

具体软件配置

花了一些时间才理解需要的软件,所以这里先列一下各个软件的名字和功能(一些没用到或不再进化的软件就不列出来了):

  • sunshine/moonlight:这两者既是服务器/客户端,也是协议。sunshine 运行在服务端,硬编码录屏并将得到的视频流发给客户端 moonlight,同时也接收 moonlight 传来的控制信号。sunshine 还提供简单的应用启动能力,也就是说可以在 moonlight 指定 sunshine 启动特定游戏。
  • steam:游戏管理器,也是游戏启动器。可以通过它来管理和启动游戏。其重要之处在于实现了一个叫做 proton 的兼容层,比 wine 更适合执行 Windows 游戏。换句话说,目前在 Linux 上启动 Windows 游戏,主要方式还是用 steam 通过 proton 执行 exe 文件。
  • umu-launcher,是 Linux 上的 Windows 游戏启动器。用它的话就不需要 steam 了。但这个软件还在发展中,没有被大量整合到其他方案中。
  • steam-headless 和 games-on-whales 的 wolf,都是通过 docker 方式提供的,在 Linux 服务器上无头运行游戏的完整方案,下面会单独展开。

以下是我尝试过的几个自建云游戏服务器的方案。

Windows + sunshine

这是以前使用的方案,简单但限制太多(比如显示器不能关闭之类),所以只是简单提一下。

在 Windows 系统上装一个 sunshine,在 sunshine 的 dashboard 上添加游戏,并简单配置(比如编码方式和手柄类型)。

在要使用的机器(比如 Switch 或电视盒)上,安装对应版本的 moonlight,启动并尝试连接。moonlight 会提示一个 pin 码。回到 sunshine 的 dashboard 上输入此 pin 码,moonlight 即可正确连接并启动 sunshine 添加的游戏。

Steam-headless

这个方案整合了 sunshine 和 steam,还提供了一个 web vnc 界面方便控制,只有一个虚拟显示器。只有一个 docker image,本质上是包含了一个完整桌面,在这个桌面环境下运行 steam,再通过 steam 运行游戏。

飞牛论坛上有文章介绍其部署过程,文章略微有些过时,但概念没问题。

相对于 wolf 而言,由于是完整桌面,性能上有一些损失。

使用逻辑非常清晰(但也不是太简单),参照 github 文档,选择对应的 docker-compose 和 .env 文件,基本上只修改 .env 即可用 docker compose 运行。

但是,我遇到的麻烦包括但不限于:

  • 使用 privilege 版本时,docker compose 起不来,只能用非 privilege 版本。
  • apt 源非常慢,虽然可以替换 apt 配置,但还是麻烦。
  • 启动时要使用 flatpak 安装大量软件,我尝试了多种方法,都没能成功为 flatpak 切换镜像源,最后是通过软路由走代理才勉强提升了一点速度。
  • 桌面启动时会自动安装 steam,但默认情况下无法弹出确认对话框。只能用 docker exec 连接容器后用 root 用户安装。
  • 容器内部显卡回落到 llvmpipe(参见 issue 213),很可能是因为此原因,导致 proton 根本无法启动游戏。

最后一条是最要命的,这是我放弃这个方案的主要原因。我认为可能是因为该方案近期从 debian bookworm 升级到 trixie 的原因,虽然 issue 似乎有人在跟,但我是实在没有精力深究了。

games-on-whales 的 wolf

跟 steam-headless 相比,这个方案在概念上相当复杂,但似乎带来了一些灵活性和性能优势,比如前面提到的多用户可以同时连接(理论上可以,没有实际尝试)。

  • 主 docker 容器,也就是 wolf,仅仅负责对外的 sunshine/moonlight 服务。这里仅仅是兼容 sunshine/moonlight 协议,而不是直接集成 sunshine。因此使用时需要注意它没有 sunshine 的 dashboard。
  • wolf 需要掌控主机的 docker。它不只是在自己的 container 封闭环境中运行,还要操作主机 docker 去动态 创建/启动/停止 一系列容器。也就是说,它还是一个容器的编排器。它通过在主机环境中动态创建一些本地 socket,与其他容器进行通信。其他容器主要包括:
    • 负责音频流处理的 PulseAudio。
    • 简化的桌面环境 Wolf UI。
    • 游戏基础镜像。
    • firefox/steam 等专用镜像。
  • Wolf UI 比完整桌面省资源。通过 Wolf UI,可以启动 Firefox/Steam/…… 等各种应用。
  • 为 wolf 添加游戏,需要基于 games-on-whales 提供的游戏基础镜像,mount 游戏本身文件,并使用环境变量 START_COMMAND 启动。
    • 理论上,可以组合 umu-launcher,将 Windows 游戏封装成 wolf 可用的镜像。但目前 umu-launcher 的使用还是太过繁琐,依赖太多。

也就是说,wolf 把云游戏的各个环节,包括:传输协议/音频处理/桌面环境/游戏环境……全部拆分成 docker 容器,然后在运行期动态处理。

使用方法

最好先 docker pull games-on-whales 提供的一系列镜像,避免后续自动 pull 浪费时间:

  • ghcr.io/games-on-whales/wolf:stable
  • ghcr.io/games-on-whales/wolf-ui:main
  • ghcr.io/games-on-whales/pulseaudio:master
  • ghcr.io/games-on-whales/steam:edge
  • ghcr.io/games-on-whales/base-app:edge
  • ghcr.io/games-on-whales/firefox:edge

其他还有一些,我自己只装了上面这几个。

主要的 docker-compose.yml 是从官方例子复制的。注意不要改 volume,尤其是 /etc/wolf/

version: "3"
services:
  wolf:
    image: ghcr.io/games-on-whales/wolf:stable
    container_name: wolf
    volumes:
      - /etc/wolf/:/etc/wolf/:rw
      - /var/run/docker.sock:/var/run/docker.sock:rw
      - /dev/:/dev/:rw
      - /run/udev:/run/udev:rw
    device_cgroup_rules:
      - 'c 13:* rmw'
    devices:
      - /dev/dri
      - /dev/uinput
      - /dev/uhid
    network_mode: host
    restart: unless-stopped

docker compose 启动后,wolf 会启动主容器和 pulse audio 容器,同时会在 /etc/wolf 目录生成一套默认配置。主要配置文件在 /etc/wolf/cfg/config.toml。这里面描述了所有由 wolf 进行编排的容器配置,以及编解码配置和用户证书等。

此时可以使用 moonlight 去搜索,可以看到局域网里存在可连接的服务。

moonlight 尝试连接时,会弹出一个 pin 码。此时需要查看 wolf 容器的 docker log,会打印一个链接。这个链接是 wolf 服务器提供的,通过这个链接去输入 pin 码,moonlight 即可认证通过。然后后续连接就可以不用再输入了。

moonlight 连接上之后,可以看到有 Test ball 和 Wolf UI 两个应用可选。前者用于简单测试服务是否正常工作。后者就是真正的选择应用的桌面。这两个应用的配置位于 config.toml 的 profiles 段落里面,在 id 为 moonlight-profile-id 的部分。

选择并进入 Wolf UI 之后,看到真正的应用列表,这部分配置同样位于 config.toml 的 profiles 段落里面,不包括 id 为 moonlight-profile-id 的部分。

注:类似 steam 这类应用,由于依赖一些桌面环境,不能通过 moonlight 直接选择,只能通过 Wolf UI 选择。

Wolf UI 参考界面如下,通过这个界面进入 steam:

如果要通过 steam 添加 non-steam 游戏(即是本地游戏),需要:

  1. 在 config.toml 文件中,找到 steam 对应的 profiles.apps.runner 段落,修改 mounts 数组,添加游戏目录映射到 steam 容器中,注意要用绝对地址,如:/home/my/games:/home/retro/games:rw
  2. 重启容器,使得 config 的修改生效。
  3. 进入 steam,默认处于大屏幕环境下,无法添加。需要通过菜单退出大屏幕,在窗口环境下才可以添加 non-steam 游戏并选择对应 exe 文件。
  4. 修改添加的游戏属性,强制使用兼容性工具,可以选择 Proton Experimental,有问题的话可以尝试其他版本。

另外 config.toml 中还可以通过一些参数调整 steam 环境,比如:

  • 在 env 数组中增加 TZ=Asia/Shanghai 配置调整时区。
  • 在 env 数组中增加 START_COMMAND=/usr/games/steam -noverifyfiles -nofriendsui -udpforce 以提升启动速度。
  • 在 mounts 数组中增加 /etc/localtime:/etc/localtime:ro 做时间的 fail-safe。

总结

配置好 wolf 之后,我可以在 switch 上玩一些 Windows 游戏了。但我 NAS 的 CPU 仅是 J3355,性能实在孱弱。所以游戏仅仅是能玩而已。

不过 wolf 确实让我看到一些潜在的可能性,未来 NAS 的性能必然会进一步提升,如果内置足够强的显卡,改造成云游戏服务器并不是很困难的事情。

Top