从零搭建DNF私服:基于Docker容器化的一键部署实战指南
【免费下载链接】dnf项目地址: https://gitcode.com/gh_mirrors/dnf/dnf
如果你曾经尝试过搭建地下城与勇士(DNF)的私服,大概率体会过那种"装到一半就想放弃"的滋味:要先准备一台干净的Linux服务器,手动编译各种依赖,拷贝几十个配置文件,还得处理版本不对导致的诡异报错。gh_mirrors/dnf/dnf 项目把这些繁琐的步骤全部打包进了一个 Docker 镜像,通过环境变量和初始化脚本即可完成服务端的快速部署,让"今天clone、今天开服测试"成为可能。本文将以实战视角,带你走完从服务器初始化、容器启动、到客户端成功登录的完整链路。
一、先搞清楚:这个项目到底替你解决了什么
传统方式搭建 DNF 服务端,你需要自己解决三件麻烦事:
- 环境依赖:游戏服务端依赖特定版本的 CentOS 和系统库,一旦系统环境有差异,各种莫名其妙的崩溃随之而来。
- 服务编排:DNF 服务端并非单一进程,而是由游戏服、频道、中继、穿透等多个进程协同工作,手动启动和监控非常痛苦。
- 初始化数据:数据库建库、账号创建、PVF 资源部署,每一步都需要人工干预,错一步就得重来。
gh_mirrors/dnf/dnf 项目以官方 CentOS-5/6/7 为基础镜像,将上述所有内容固化到镜像内部,对外只暴露一组环境变量。你只需要回答几个问题——公网 IP 是多少、GM 账号密码用什么、开哪几个频道——剩下的交给初始化脚本。项目还内置了 Supervisor 进程管理器,所有服务进程的状态、日志、重启操作都能在一个 Web 页面上完成,这也是它适合新手入门的关键原因。
二、一张图看懂服务端架构:那些进程都是干什么的
在动手部署之前,建议先花两分钟理解服务端的组成,否则后面排查问题会像无头苍蝇。项目文档 doc/ArchitectureDiagram.md 中给出了完整的流程图:
整个服务端可以归纳为四个层次:
接入与转发层
- Relay(中继):当客户端之间无法建立 P2P 直连时负责数据中转,需要暴露公网端口(希洛克大区为 7300)。
- Stun(穿透):负责 NAT 穿透(UDP Hole Punching),是组队功能的关键服务,占用 2311-2313 端口。
- Channel(频道):向客户端下发分流(频道)信息,端口 7001。
核心业务层
- Game(游戏服):处理登录登出、地下城逻辑、角色创建、现金购买,即你在日志中看到的
df_game_r进程。 - Bridge:负责分流信息档案的收集与传送,同时统计在线人数等数据。
- Community / Monitor / Guild / Auction等辅助服务:分别处理决斗场、跨服消息、公会、拍卖行等功能。
数据层
- DBMW:数据库中间件,分为 guild、mnt、stat 三种,是游戏逻辑与 MySQL 之间的桥梁。
监控层
- Supervisor:统一管理所有进程,访问
http://IP:2000即可打开管理页面。
对于普通使用者,你不需要逐一理解每个进程的细节,但记住一句话就够了:凡是架构图上标注了端口号的组件,都需要在防火墙和云厂商安全组中放行。这也是绝大多数"灰频道""连不上网关"问题的根源。
三、部署第一步:初始化一台"合格"的Linux服务器
项目文档 doc/PrepareLinux.md 列出了三项必须完成的准备工作,建议按顺序执行:
1. 安装 Docker
yum update -y curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh systemctl enable docker systemctl restart docker2. 关闭防火墙(重点)
游戏服务端使用大量 TCP/UDP 端口,如果防火墙未关闭,即便容器端口映射正确也无法访问:
systemctl disable firewalld systemctl stop firewalld3. 配置 Swap 交换空间(内存不足 8GB 时必须做)
服务端启动时对内存的需求远超你的想象,尤其是Init DataManager阶段,内存不够会直接卡死。创建一个 8GB 的 swap 文件:
/usr/bin/fallocate --length 8GiB /var/swap.1 mkswap /var/swap.1 swapon /var/swap.1 sed -i '$a /var/swap.1 swap swap default 0 0' /etc/fstab随后确认sysctl vm.swappiness输出不为 0;如果为 0,需要在/etc/sysctl.conf追加vm.swappiness = 100并执行sysctl -p生效。
拉取镜像:国内用户推荐从阿里云镜像源拉取,速度更快:
docker pull registry.cn-hangzhou.aliyuncs.com/1995chen/dnf:centos7-2.1.9.fix1 docker tag registry.cn-hangzhou.aliyuncs.com/1995chen/dnf:centos7-2.1.9.fix1 1995chen/dnf:centos7-2.1.9.fix1四、最快跑起来:一条 docker run 命令完成部署
准备工作就绪后,先创建三个数据挂载目录,用于持久化日志、数据库和资源文件:
mkdir -p /data/log /data/mysql /data/data然后执行以下命令启动服务(将x.x.x.x替换为你的公网 IP,局域网测试则填写局域网 IP):
docker run -d \ -e PUBLIC_IP=x.x.x.x \ -e WEB_USER=root -e WEB_PASS=123456 \ -e DNF_DB_ROOT_PASSWORD=88888888 \ -e GM_ACCOUNT=gmuser -e GM_PASSWORD=gmpass \ -e CLIENT_POOL_SIZE=10 \ -v /data/log:/home/neople/game/log:Z \ -v /data/mysql:/var/lib/mysql:Z \ -v /data/data:/data:Z \ -p 2000:180 -p 3000:3306/tcp -p 7600:7600/tcp \ -p 881:881/tcp -p 7001:7001/tcp -p 7001:7001/udp \ -p 30011:30011/tcp -p 31011:31011/udp \ -p 30052:30052/tcp -p 31052:31052/udp \ -p 7300:7300/tcp -p 7300:7300/udp \ -p 2311-2313:2311-2313/udp \ --cap-add=NET_ADMIN --hostname=dnf \ --cpus=1 --memory=1g --memory-swap=-1 --shm-size=8g \ --name=dnf 1995chen/dnf:centos5-2.1.9.fix1四个必须注意的参数:
--shm-size=8g:不可删除。Docker 默认共享内存只有 64M,过小会导致服务启动失败。PUBLIC_IP:必须填写客户端能访问到的 IP,填错会直接表现为"灰频道"。CLIENT_POOL_SIZE:客户端缓冲池大小,单人测试可设为 3,多人按需增加,上限 1000。DNF_DB_ROOT_PASSWORD:容器启动时会自动把 MySQL root 密码修改为该值。
五、如何确认服务端真的启动成功了
这一步很多人会忽略,导致后续排查浪费时间。项目给出了三层验证方法:
第一层:看"五国"日志
进入日志目录,查看当天的初始化日志:
tail -f /data/log/siroco11/Log$(date +%Y%m%d).init当看到类似下面的输出时,说明基础服务已经就绪(初始化大约需要 1 分钟,请耐心等待):
[09:40:23] GeoIP Allow Country Code : CN [09:40:23] GeoIP Allow Country Code : HK [09:40:32] [!] Connect To Guild Server ... [09:40:32] [!] Connect To Monitor Server ...第二层:确认游戏进程存活
ps -ef | grep df_game如果输出中存在./df_game_r siroco11 start这样的进程,代表游戏服正常运行。
第三层:访问 Supervisor 管理页面
浏览器打开http://IP:2000(默认账号 root / 123456),可以看到所有进程的运行状态,并支持在线查看日志、重启进程。后续服务被系统杀掉时,也可以在这里手动拉起。
六、客户端接入:网关、补丁与登录器三步走
服务端就绪后,客户端还需要做三件事。相关工具都收录在 other/登录器 目录中,客户端补丁则位于 other/等级补丁。
- 安装 DOF 补丁:解压
DOF补丁大合集V7.6.7z,编辑其中的DNF.toml,将服务器地址改为你的PUBLIC_IP,然后把DNF.toml、DNF.exe等文件复制到游戏客户端根目录。 - 配置统一网关:打开
统一网关在线管理工具v6.4.exe,在"网关设置"页填写:网关地址为PUBLIC_IP、网关端口 881、登录账号 gmuser、登录密码 gmpass、通信密钥763WXRBW3PFTC3IXPFWH、登录器端口 7600。保存后在"登录器设置"页生成登录器。 - 放置登录器:将生成的登录器及
Config.ini复制到游戏根目录,双击运行即可。
项目默认的网关参数汇总如下,如果你修改了环境变量,请以实际配置为准:
| 配置项 | 默认值 | 说明 |
|---|---|---|
| 网关端口 | 881 | 统一网关 TCP 端口 |
| 登录器端口 | 7600 | 统一登录器端口 |
| 通信密钥 | 763WXRBW3PFTC3IXPFWH | 网关与登录器之间的密钥 |
| GM 账号 / 密码 | gmuser / gmpass | 不能包含特殊字符 |
七、进阶玩法:从单机到多频道、多大区的扩展路径
当你跑通单机后,自然会想扩大规模。项目在 deploy/dnf/docker-compose 目录下提供了四套现成的编排方案,覆盖了从入门到生产的各种场景:
- basic:基础部署,一个容器跑完整服务,适合个人测试。
- multi_channel:多频道部署,通过
OPEN_CHANNEL变量指定开放哪些频道,每个频道需要映射对应的 TCP/UDP 端口。 - standalone_mysql:站库分离,将 MySQL 独立成容器,适合后续迁移。
- multi_server_group:多大区部署,支持在一台或多台服务器上同时运行卡恩(cain)、狄瑞吉(diregie)、希洛克(siroco)三个大区。
以 basic 方案为例,核心配置如下(deploy/dnf/docker-compose/basic/docker-compose.yaml):
version: "2.3" services: dnf-1: image: 1995chen/dnf:centos5-2.1.9.fix1 environment: - TZ=Asia/Shanghai - SERVER_GROUP=3 - DNF_DB_ROOT_PASSWORD=88888888 - GM_ACCOUNT=gmuser - GM_PASSWORD=gmpass - GM_CONNECT_KEY=763WXRBW3PFTC3IXPFWH - GM_LANDER_VERSION=20180307 - PUBLIC_IP=127.0.0.1 - OPEN_CHANNEL='11,52' shm_size: 8g mem_limit: 1g cpu_count: 1 restart: always ports: - 2000:180/tcp - 3000:3306/tcp - 7600:7600/tcp - 881:881/tcp - 7001:7001/tcp - 7001:7001/udp - 7300:7300/tcp - 7300:7300/udp - 30011:30011/tcp - 31011:31011/udp - 30052:30052/tcp - 31052:31052/udp - 2311-2313:2311-2313/udp volumes: - ./data:/data:Z - ./mysql:/var/lib/mysql:Z - ./log:/home/neople/game/log:Z关于大区,有两个容易踩坑的知识点:
- 大区编号映射:1=卡恩(cain)、2=狄瑞吉(diregie)、3=希洛克(siroco)。默认
SERVER_GROUP=3。 - 数据库兼容:市面上的主流 PVF 和 GM 工具大多连接 cain 数据库,如果遇到 GM 工具无法使用,可额外设置环境变量
SERVER_GROUP_DB=cain显式指定。
如果需要更大规模的部署(如 K8s),项目在 deploy/dnf/k8s-deploy 目录提供了完整的 StatefulSet、Service 与存储配置,建议先阅读00-1开始一定要看前期准备.md与00-2开始一定要看注意事项.md两份文档。
八、性能与成本:一个人玩和一百个人玩,配置差多少
服务端的内存占用主要受两个因素影响:频道数量和CLIENT_POOL_SIZE。其中df_bridge_r和df_channel_r两个进程各占约 1.3GB 内存,这是固定开销;CLIENT_POOL_SIZE则决定缓冲池大小,直接关系并发能力。参考配置如下:
| 场景 | 内存 | CLIENT_POOL_SIZE | 建议 shm-size |
|---|---|---|---|
| 单人测试 | 1G | 3 | 2G~8G |
| 小型亲友服 | 2G~4G | 10~30 | 8G |
| 大规模开服 | 8G+ | 按需调大 | 16G |
两个高性价比的优化手段:
- 调整 swap 优先级:文档建议将
vm.swappiness设为 100(优先使用虚拟内存),对个位数玩家的场景,几乎无感知差异,却能大幅降低物理内存门槛。 - 升级后清理旧脚本:如果你从旧版本升级,
CLIENT_POOL_SIZE不生效时,删除挂载目录下的/data/run/start_bridge.sh和/data/run/start_channel.sh后重启即可(只需删一次)。
另外,如果你没有固定公网 IP,可以设置AUTO_PUBLIC_IP=true让容器启动时自动获取公网 IP;项目还支持 Netbird 和 Tailscale 虚拟组网,适合朋友间通过虚拟内网联机。
九、踩坑实录:五个高频问题的排查手册
结合项目 README 与社区反馈,这里整理五个最高频的问题,全部采用"现象→原因→解法"的格式,建议收藏备用。
问题 1:服务端一直卡在 Init DataManager 日志循环
- 原因:物理内存或 swap 不足,进程无法完成数据加载。
- 解法:将 swap 扩容到 10G 或更大,同时把
--shm-size调整为 10g;若 swap 占用始终为 0,执行sysctl -p后重启服务器。
问题 2:出现"灰频道"或点击频道无法进入
- 原因:端口不通或 IP 配置错误,客户端拿不到游戏服的真实地址。
- 解法:依次检查 Linux 防火墙是否关闭、云厂商安全组端口是否放行、
PUBLIC_IP是否填错、客户端 hosts 是否配置了start.dnf.tw(5.x 登录器需要)、公钥私钥文件是否匹配。
问题 3:点击网关登录没反应,不出游戏
- 原因:多半是客户端环境问题,而非服务端问题。
- 解法:Win7 用管理员权限运行网关、Win10 反之;不要通过虚拟机 Console/VNC 访问 Windows;用
dxdiag确认 DirectX 功能全部开启;确认客户端补丁已正确覆盖。
问题 4:登录器提示"版本过期"
- 原因:登录器版本与网关配置不一致。
- 解法:在网关"登录器设置"页将登录器版本设为
20180307(与GM_LANDER_VERSION一致),重新生成登录器。
问题 5:GEO 拦截导致连接频道时网络中断
- 原因:服务端内置了 GeoIP 地区限制,你的 IP 不在允许列表。
- 解法:从频道日志中找到
Fail Account...IP:xxx的拦截记录,执行 SQL 添加白名单(以 IP 192.168.48.1 为例):
insert into d_taiwan.geo_allow values ('192.168.48.1', "*", "2016-04-09 23:53:04");执行后重启服务端生效。更完整的排查清单可参考项目 README 的"常见问题"部分。
十、写在最后:能力越大,责任越大
至此,你已经走完了从服务器初始化、容器部署、日志验证到客户端接入的完整流程。这个项目最大的价值,是把一个原本需要数天甚至数周的专业运维工作,压缩成了几分钟的容器操作——这正是容器化技术的魅力所在。更进一步,你还可以通过 plugin 目录挂载 dnf-console(Web 控制台)、DP 数据包处理等插件,或参考 doc/OtherDeploy.md 探索 K8s 生产级部署。
最后必须提醒:该项目仅用于学习与研究目的。虽然服务端支持外网访问,但请勿用于商业开服运营,以免侵犯游戏公司的知识产权并触犯相关法律法规。在动手之前,建议先阅读项目的 LICENSE 文件,明确使用边界。祝你在技术探索的道路上玩得开心,也欢迎加入社区 QQ 群(933010289 / 971177373)与其他爱好者交流,共同完善这个项目。
【免费下载链接】dnf项目地址: https://gitcode.com/gh_mirrors/dnf/dnf
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考