🔑 关键洞察
✦ AI·GEN这篇记录了作者帮朋友用 Docker 在自己 24/7 的家用机上架设幻兽帕鲁(Palworld)专用伺服器的完整过程,整理成一份能照做的教学。缘起是朋友原本用 Radmin VPN 连线,但那类 P2P 服务穿不过 NAT 就会退回中继、流量绕经第三方,作者索性用自己的常开主机自架。文章先破除一个迷思:主机商规格页清一色写「16GB 起」,但小团队日常很省,作者实测 3~5 人约 1.2GB;真正要防的是 Palworld 知名的记忆体泄漏,靠容器 mem_limit + 每日重启压住即可。接着给出一份去芜存菁的 docker-compose(port 记得加 /udp、RCON 绑 127.0.0.1),把架好之后最卡人的 UDP 连线三关逐一走通:ufw 放行 udp、路由器 port forwarding(必须 UDP)、DDNS,并拆穿两个高频误区——Cloudflare 一定要用灰云(橘云代理不转 UDP,开了必连不上)、UDP 游戏封包根本不经过 nginx。后半谈世界设定的坑(改 ini 会被环境变数重新生成盖掉)、朋友「版本不符」进不去怎么修(比对 buildid、重启触发 SteamCMD 更新、更新前先 RCON 广播存档),以及别让 18GB 游戏本体天天进备份碟。结尾附一份自架检查清单。
朋友看到幻兽帕鲁(Palworld)出了 1.0,揪我一起玩。他们两年前就破过一轮,想趁这次大改版重破一次,而我那阵子刚好有空。
老实说我原本对这游戏印象不太好,当年那个「抄宝可梦」的争议摆在那里。但后来它的官司打赢了,加上 1.0 的更新幅度是真的大,我想或许没想像中严重,就跟着入手了。
朋友一开始是用 Radmin VPN 把大家串起来连的。这方法不能说不行,但它总让我有点资安上的疙瘩。Radmin 这类虚拟区网走的是 P2P:两端能直连就直连,穿不过对方的 NAT 或防火墙,就退回走它自己的。以我朋友家的网路,我不太相信每组连线都打得穿,大概率会落到中继。中继的代价有两层:一是慢(封包多绕一圈远路),二是游戏流量得经过一家免费闭源服务的伺服器。它确实全程加密,但要不要把连线交给第三方绕一趟,对我来说是个不必要的风险。而我手上刚好有一台 24/7 开着的家用机,趁他们进度还没推多久,我说:不如我来架一台专用伺服器,大家直接连我家。
于是有了这篇。用 Docker 架一个幻兽帕鲁专用伺服器其实不难,docker compose up 几分钟就跑起来了。真正难的是下一步:架好了,朋友却连不进来。 这一关卡住的人,远比卡在「怎么架」的人多。这篇把整条路走一遍,从资源评估、docker-compose,到最容易卡关的那道 UDP 连线,再到「朋友说版本不符进不去」怎么修。所有指令都能照着跑,密码跟 IP 我用占位符,你换成自己的。
先说用哪个 image,和记忆体到底吃多少#
先讲一句:多数人自架其实是用官方的专用伺服器工具(SteamCMD 直接拉 PalServer),不一定要 Docker。 我走 Docker 纯粹是自己用习惯了、跟机器上其他服务一致好管理;如果你也有一台常开的 server、docker 用得顺手,这条路会很舒服。我用的 image 是社群维护的 ,它把 SteamCMD 下载、设定档生成、备份、RCON 都包好了。
记忆体要先破除一个迷思:你查主机商的规格页,清一色写「16GB 起、32GB 更稳」,那数字偏保守(他们也在卖 RAM)。实际上小团队日常很省,我这台 Linux docker 跑 3~5 个人,实测大约落在 1.2GB(没有长时间监控,是随手看的值)。
那为什么还要在意记忆体?因为幻兽帕鲁有个的老毛病:进程本身会随时间慢慢变肥,跟你们在游戏里盖了多少东西无关。社群实测一个 4 人服连续跑、都不重启,一周内能从 5G 爬到 8~12G。所以真正该做的不是准备 32G,而是设一个 mem_limit 挡住上限、再配每天定时重启(重启会释放记忆体,有人在线就延后),把泄漏压在合理范围——这样它跑再久也不会拖垮同机的其他服务。
一份最小可用的 docker-compose#
核心设定其实不多。下面这份去掉了枝节,留下真正该懂的几行:
services:
palworld:
image: thijsvanloef/palworld-server-docker:latest
restart: unless-stopped
container_name: palworld
stop_grace_period: 30s # 收到停止讯号后,留 30 秒让它存档
ports:
- "8211:8211/udp" # 游戏连线,UDP(重点,下面详谈)
- "27015:27015/udp" # Steam query,UDP
- "127.0.0.1:25575:25575" # RCON,只绑本机,外面碰不到
environment:
PLAYERS: "16"
SERVER_NAME: "My Palworld"
SERVER_PASSWORD: "<你的伺服器密码>"
ADMIN_PASSWORD: "<你的管理密码>"
UPDATE_ON_BOOT: "true" # 容器启动时检查游戏更新
RCON_ENABLED: "true" # 自动备份/重启要靠它优雅关机
BACKUP_ENABLED: "true"
AUTO_REBOOT_ENABLED: "true" # 每日重启,释放膨胀的记忆体
mem_limit: 16g
volumes:
- ./data:/palworld # 游戏本体 + 存档都在这几个当下不明显、之后会踩到的点:
8211和27015后面那个/udp不能漏。Palworld 走的是 UDP,漏了写成 TCP,server 起得来、你本机也连得上,但外面的人一个都进不来。- RCON 绑
127.0.0.1:它是拿来让自动备份/重启能先广播警告再优雅关机的管理通道,只给本机用,不该对外开。 mem_limit跟AUTO_REBOOT_ENABLED是一组的,专门对付上面说的记忆体膨胀。
真正卡人的是网路:UDP 连线三关#
docker compose up -d 之后,server 就在 8211 上跑了,你自己在同一个网段连 区网IP:8211 通常没问题。然后朋友一连,连不进来。
因为封包要从网际网路走到你家那个容器,中间有三道关,少一道就进不来:
先让封包进得了主机。 开两个 UDP port:
sudo ufw allow 8211/udp comment 'Palworld game'
sudo ufw allow 27015/udp comment 'Palworld query'协定一定是 udp。这是三关里最常被写成 tcp 的一关。
封包从网际网路进到你家,要靠路由器把它转发给那台主机。到路由器管理介面加两条转发规则:
| 外部 (WAN) | → 内部主机 | 协定 |
|---|---|---|
| 8211 | 192.168.x.x : 8211 | UDP |
| 27015 | 192.168.x.x : 27015 | UDP |
家用网路的公网 IP 通常会变动,所以挂一个 ,让朋友记一个固定网址就好,不用每次问你 IP。如果你用 Cloudflare 管网域,这里有个致命细节在下一段。
WARNING
Cloudflare 要用「灰云」(DNS only),不能开「橘云」(Proxied) Cloudflare 的橘云代理只转发 HTTP/HTTPS 流量,它不转任意的 UDP 封包。你把 Palworld 的网域开成橘云,朋友会 100% 连不上,而且错得很安静(网页类服务照常,只有游戏连不进来,很难联想到是这里)。一定要点成灰云,让网域直接解析到你家 IP。
两个高频误区,先讲清楚免得你白忙:
NOTE
不用改 nginx,一个字都不用动
很多人架网页服务习惯了,一遇到「对外」就想到反向代理。但 ,而 Palworld 是 UDP 游戏封包,走「路由器 → ufw → 容器」直通,跟 nginx 完全无关。这次 /etc/nginx 一个字都不用改。
那 27015 到底要不要开?它是 ,只影响「能不能在 Steam 的伺服器浏览器看到你的 server 状态」。想极简的话,先只开 8211,朋友直连 你的网址:8211 就能玩;之后真的有人想从 Steam 最爱清单看在线状态,再补 27015。
世界设定的坑:直接改 ini 会被盖掉#
server 通了之后,你大概想调一下经验倍率之类的。这里有个一定会踩的坑:这个 image 每次开机,会用环境变数重新生成 PalWorldSettings.ini。 你手动去改那个 ini 档,下一次容器重启就被盖回去了,改了像没改。
正确做法是把设定写进 docker-compose.yml 的 environment 区块,让它生成的时候就带上你的值。常见的几项:
常用的世界设定(写进 compose 的 environment)
| 环境变数 | 效果 | 范例值 |
|---|---|---|
EXP_RATE | 经验值倍率 | 3.0 |
COLLECTION_DROP_RATE | 采集掉落倍率 | 3.0 |
DEATH_PENALTY | 死亡惩罚 | Item(只掉道具、装备保留) |
PAL_EGG_DEFAULT_HATCHING_TIME | 蛋孵化时间(小时) | 1(预设 72) |
BASE_CAMP_WORKER_MAX_NUM | 基地工作 Pal 上限 | 20 |
SERVER_PLAYER_MAX_NUM | 人数上限 | 32 |
PVP / ENABLE_FRIENDLY_FIRE | PvP / 友军伤害 | true / false |
改完 docker compose up -d,容器重建、用新环境变数重新生成 ini,设定就生效了。要验证有没有吃到,可以进容器看生成出来的 ini(docker exec palworld cat .../PalWorldSettings.ini),确认是你的值再收工。
朋友说「版本不符」进不去:是 server 落后了#
玩了几天,某个朋友回报「进不去,显示版本不符」。这几乎都是同一个原因:他的 client 已经自动更新到新版,而你的 server 还停在旧版。
怎么确认?比对 :本地 server 的 buildid 对上 Steam 最新的 buildid,不一样就是落后了。
这里有个很坑的假象要拆穿:容器日志可能写着 container is up to date,你以为已经是最新——那句话指的是 Docker image 最新,不是游戏档最新。 游戏更新是 UPDATE_ON_BOOT 在容器启动时跑一次 SteamCMD 抓的,如果你的容器已经连续跑了好几天没重启,它就没机会抓到这几天的新版。
修法是重启容器,触发一次 SteamCMD 更新:
docker compose up -d --force-recreate但重启会把线上的人踢下线,别直接动手。优雅的做法是先用 RCON 广播、存档,再重启:
TIP
更新前先广播 + 存档,别在人家玩到一半直接踢
透过 RCON 送一句广播(「伺服器 5 分钟后更新重启」)给线上玩家、触发一次存档,再 --force-recreate。被踢的人等他们的 client 也更新完(通常自动、几分钟),直接重连就好,存档不受影响。更新约一两分钟(下载 ~5GB),完成后本地 buildid 就跟朋友的 client 对上了。
如果不想每次都手动盯,把 AUTO_UPDATE_ENABLED 打开,server 会定时自己检查更新(一样可以设有人在线先广播再更新),游戏一出新版就不会再卡朋友进不来。
别让 18GB 游戏本体天天进你的备份碟#
最后一个容易忽略的维运陷阱。如果你跟我一样有一套每日 rsync 备份整个伺服器目录的机制,加了 Palworld 之后要注意:那个 data/ 资料夹装着整包游戏本体,将近 18GB,不处理的话它会天天被塞进你的备份碟。
真正需要备份的只有存档,不是那 18GB 游戏档(游戏档随时能重新下载)。所以:
- 主
rsync排除掉palworld/data(游戏本体) - 单独备份存档目录(
Pal/Saved),那才是删了会心痛的东西 - 把 Palworld 存档也纳入你既有的旧备份清理回圈(例如只留 7 天)
.gitignore 那边也顺手确认 data/ 有被排除,免得 18GB 游戏档跟着进版控。
一页式清单#
把整条路浓缩成可照抄的顺序:
幻兽帕鲁自架检查清单
- 记忆体别被吓到:小团队实测 1~2G 就够(主机商的 16G 偏保守);真正要防的是记忆体泄漏,靠容器
mem_limit+ 每日重启压住。 - compose:port 记得加
/udp;RCON 绑127.0.0.1;密码写环境变数。 - 网路三关:ufw 放行
udp→ 路由器 port forwarding(UDP!) → DDNS。 - Cloudflare 用灰云,橘云代理不转 UDP,开了必连不上。
- 不用碰 nginx,UDP 游戏封包不经过反向代理。
- 世界设定写进 compose 的 environment,别手改 ini(会被重新生成盖掉)。
- 朋友版本不符 = server 落后;比对 buildid,重启容器触发 SteamCMD 更新,更新前先 RCON 广播 + 存档。
- 备份排除游戏本体(18GB),只单独备份存档目录。
- thijsvanloef/palworld-server-docker —— 这篇用的 Docker 映像GitHub
- Palworld 官方专用伺服器说明Palworld Wiki
- Cloudflare —— 为什么 Proxy(橘云)只走 HTTP/HTTPSCloudflare Docs
还没有留言
✨ 成为第一个留言的人吧