DNF私服搭建实战:从三天踩坑到一条 Docker 命令拉起服务端
【免费下载链接】dnf项目地址: https://gitcode.com/gh_mirrors/dnf/dnf
如果你也动过 DNF 私服搭建的念头,gh_mirrors/dnf/dnf这个把整套地下城与勇士服务端打包进 Docker 镜像的开源项目,很可能就是让你从"翻了三天的教程还停在准备阶段"直接跳到"今晚就能进游戏"的那条捷径。它的核心价值很朴素:把过去散落在几十个配置文件里的复杂度,收敛成几个环境变量。
先说说我手动搭 DNF 服务端时踩过的坑
在没有容器方案之前,搭一个能跑起来的 DNF 服务端是什么体验?我形容它是"一场没有文档的考古":先要找到一套能用的服务端程序,装一个老版本 Linux,再对着各种.cfg文件改 IP、改端口、改数据库账号;PVF 资源包要处理加密问题,等级补丁要和客户端版本对齐,MySQL 要手动建库授权……任何一步错了,报错都是玄学级别的。
其中最劝退的是"不出五国"这个黑话。所谓五国,指的是服务端初始化日志里连续出现的GeoIP Allow Country Code那几行,它相当于服务端在喊"我活过来了"。可一旦内存不够、swap 没配、PVF 不对,这几行就是迟迟不出现,你只能对着屏幕干瞪眼。
我最初的几次尝试,基本都死在这一步。直到我换了个思路:与其手动管理这堆进程,不如把整套环境装进容器里——这就是gh_mirrors/dnf/dnf做的事。它以官方 CentOS 5/6/7 为基础镜像,通过环境变量和初始化脚本完成自动部署,官方 README 里有一句我特别认同的声明:这个项目虽然支持外网,但只建议用来学习,别拿去开服。
DNF 私服搭建的本质:一堆进程加一堆端口
要理解它为什么能"一条命令跑起来",得先看懂 DNF 服务端到底是个什么东西。它不是一个单一体,而是一群各司其职的进程,通过固定的端口互相喊话:
- Game Server:游戏逻辑的主心骨,处理登录、创角、地下城内的战斗逻辑;
- Relay Server:当两个玩家之间无法建立 P2P 直连时,负责当中转;
- Stun Server:做 NAT 穿透(UDP 打洞),组队刷图能不能连上,它很关键;
- Channel 与 Bridge:频道情报的下发与汇总,你看到的"频道列表"就是它们维护的;
- DBMW:数据库中间件,分为 guild、mnt、stat 三种,相当于各服务的"账房先生"。
用大白话打比方:Game Server 是主城,频道是副本入口,Relay 和 Stun 是帮你把网络打通的红娘,DBMW 是管账的。以前你要手动把这些进程一个个拉起来、把端口一个个配对;而在这个镜像里,容器内的 Supervisor 把这些进程全部托管了,顺带还给你留了一个可视化的进程管理页面。这就是它"省事"的底层逻辑。
Docker 部署 DNF 服务器的第一课:把 docker run 翻译成人话
动手之前,先在 Linux 机器上装好 Docker 并关掉防火墙(项目在doc/PrepareLinux.md里给了完整的初始化步骤,包括内存不足 8GB 时如何配置 swap)。然后挂三个数据目录:日志、数据库、游戏数据,把服务端的状态和容器生命周期解耦:
mkdir -p /data/log /data/mysql /data/data接着就是那条著名的启动命令。别被它吓到,拆开看其实就三件事:告诉容器"你是谁"、把端口映射出来、给足内存。环境变量是它的精髓:
PUBLIC_IP:服务器对外 IP,局域网部署就填局域网 IP。它就像你家小区的门牌号,填错了,所有客户端都找不到你;DNF_DB_ROOT_PASSWORD:容器启动时会自动把 MySQL root 密码改成这个值,数据库端口对外是 3000 而不是 3306,容易记错;GM_ACCOUNT/GM_PASSWORD/GM_CONNECT_KEY:统一网关的账号、密码和通信密钥,客户端登录器要拿这三样来"对暗号";OPEN_CHANNEL:要开放哪些频道,默认11,52,想开更多就加;CLIENT_POOL_SIZE:服务端启动时分配的客户端缓冲池,单人玩填 3 就够,人多再往上加,它直接影响df_bridge_r和df_channel_r两个进程的内存占用;--shm-size=8g:这个参数不能删,Docker 默认共享内存只有 64M,太小服务端根本起不来,很多人卡在启动阶段就是这个原因。
端口映射同样有规律可循:881 是统一网关,7600 是统一登录器,2000 是 Supervisor 进程监控,3000 是 MySQL,7001 是频道服务,30011/31011 是 11 频道的 TCP/UDP 口,2311-2313 是 Stun。每个端口都对应一个"门牌号转接",漏一个,就有一个服务在外面找不到家。
如果你觉得 docker run 太长,项目在deploy/dnf/docker-compose/basic/docker-compose.yaml里提供了等价的 compose 版本,注释写得非常详细,群晖用户可以直接拿来改。
启动后别急着登录:先确认"五国"真的出来了
启动之后最忌讳的就是立刻打开客户端。服务端初始化大概需要一分钟,判断它是否真正活过来,有三个步骤:
第一,看日志。进入挂载的/data/log目录,找到siroco11文件夹下的Log$(date +%Y%m%d).init文件(siroco 是默认大区希洛克的名字),执行tail -f盯住它。当连续的GeoIP Allow Country Code几行出现时,恭喜你,五国出来了,服务端初始化成功。
第二,看进程。执行ps -ef | grep df_game,如果能看到df_game_r siroco11 start这样的进程,说明游戏主程序在跑。
第三,看管理页。浏览器访问http://服务器IP:2000,用WEB_USER/WEB_PASS登录 Supervisor 页面,在这里可以实时看每个进程的状态、点开日志、手动重启,比在命令行里翻日志直观得多。
从服务端到客户端:DNF 私服频道配置与网关对接的最后一公里
服务端跑通只是上半场,下半场是让客户端连上来。这里最容易忽略的一点:服务端和客户端是"对暗号"的关系,IP、密钥、版本号三样必须完全对齐,差一个字符都进不去。
项目other/登录器/目录下放了统一的网关管理工具和补丁包,客户端侧的对接大致是这么几步:
- 把 DOF 补丁里的
DNF.toml打开,把里面的服务器地址改成你部署时填写的PUBLIC_IP,再把DNF.toml、DNF.exe等文件复制到客户端根目录; - 打开统一网关在线管理工具,在"网关设置"里填上网关地址、网关端口 881、登录账号密码和通信密钥,然后在"登录器设置"里配好登录器端口 7600 和登录器版本,点击"生成登录器";
- 把生成的登录器和
Config.ini复制回客户端根目录,同时记得在 Windows 的 hosts 文件里加上start.dnf.tw的解析(统一登录器 5.x 版本必须要这一步,否则进不了频道)。
小贴士:登录器版本要和启动命令里的
GM_LANDER_VERSION一致,否则客户端会提示"登录器版本过期"。
灰频道、连不上网关:DNF 私服搭建常见翻车现场
我第二次部署时遇到频道列表一片灰,点哪个频道都没反应,排查了半天,最后发现是云服务商的安全组没放行 UDP 端口。这里把项目 README 里高频问题做个汇总,帮你少走弯路:
- 灰频道或进不去频道:优先检查 Linux 防火墙是否关闭、云厂商安全组端口是否放行、
PUBLIC_IP是否填对(Windows 客户端要能访问到这个地址)、hosts 是否配置、公钥私钥文件是否匹配; - 一直卡在
Init DataManager日志循环:内存或 swap 不足,把 swap 调到 10G 以上,并同步调大--shm-size; - 统一网关连不上数据库:数据库对外端口是 3000 而不是 3306,用户名用 root,密码是
DNF_DB_ROOT_PASSWORD的值; - 日志里出现
GeoIP Fail拦截记录:这是 GEO 区域拦截,找到被拦的 IP,把它加进geo_allow白名单表再重启服务即可,项目文档里给了现成的 SQL。
这些坑基本都有同一个根因:容器里服务是通的,但门没给外面打开。所以排查时永远从"端口能不能从外部访问"开始,比看日志更高效。
当玩家变多:多频道、多大区与站库分离
如果只是自己单机研究,默认配置就够了。但当你想拉几个朋友一起玩,或者研究更接近生产环境的架构,项目提供了完整的升级路径,而且每个阶段都有现成的部署文件:
多频道:在OPEN_CHANNEL里追加频道编号,每个频道对应一组 TCP/UDP 端口。参考deploy/dnf/docker-compose/multi_channel/docker-compose.yaml,它演示了同时开放 1、6、7 三个频道时的端口规划。
多大区:DNF 台服架构里,大区有对应的代号和数据库——1 号卡恩(cain)、2 号狄瑞吉(diregie)、3 号希洛克(siroco)。通过SERVER_GROUP和SERVER_GROUP_DB环境变量切换。项目甚至提供了三台服务器分别跑三个大区(deploy/dnf/docker-compose/multi_server_group/下的cain.yaml、diregie.yaml、siroco.yaml)以及一台机器合并跑三个大区(combine_server_group.yaml)的完整方案。
站库分离:默认 MySQL 在容器内部,想要数据库独立出来,可以参考deploy/dnf/docker-compose/standalone_mysql/docker-compose.yaml,把数据库拆成独立容器,游戏服务通过MYSQL_HOST、MYSQL_PORT连过去。
再往上,deploy/dnf/k8s-deploy/目录下还准备了 Kubernetes 部署方案,里面有命名空间脚本、MySQL StatefulSet、持久化存储和 Service 配置,00-1开始一定要看前期准备.md里写清楚了集群、NFS 这些前置条件。把 DNF 服务端跑在 K8s 上听起来有点奢侈,但如果你本来就在研究容器编排,这反而是一份很完整的练手样例。
还能怎么玩:插件和等级补丁
服务端跑稳之后,项目还有两个可以折腾的方向。
一个是插件。plugin/目录下有几个现成的:dnf-console提供一个 Web 控制台(默认 8088 端口),可以在浏览器里管理;by-gate是另一个网关实现(8188 端口);70s2_dp和dp2是数据包处理增强插件。用法统一得很:把压缩包和.conf文件复制到容器挂载目录的conf.d下,映射对应端口,重启容器即可。
另一个是等级补丁。other/等级补丁/目录按 50、60、70、80、85、90、95、99 分好了等级档位,每个目录里是配套的DNFHelper.dll和df_game_r。想调整等级上限,就选对应目录把文件换进服务端,同时保证客户端用相同版本,注意 PVF 必须是未加密的,否则登录会报"请重新安装 Init"。
下一步行动建议
如果你想动手试试,我的建议路径是:先在一台内存 4G 以上的机器上,按deploy/dnf/docker-compose/basic/docker-compose.yaml的配置跑通单频道,PUBLIC_IP填本机局域网 IP,用局域网内的另一台电脑做客户端验证;跑通之后再逐步加频道、试多大区配置。想研究完整源码和所有部署文件,可以git clone https://gitcode.com/gh_mirrors/dnf/dnf到本地慢慢看。
最后留两个思考题给你:其一,如果目标是 100 人同时在线,你会怎么规划CLIENT_POOL_SIZE、OPEN_CHANNEL和服务器内存之间的关系?其二,把游戏服务端容器化的思路,能不能迁移到你正在维护的其他"古董级"业务系统上?想清楚这两点,你从这个项目里收获的就远不止一个能玩的游戏服务端了。
【免费下载链接】dnf项目地址: https://gitcode.com/gh_mirrors/dnf/dnf
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考