朋友看到幻獸帕魯(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(沒有長時間監控,是隨手看的值)。

~1.2GB
我實測(3~5人)
隨手看,非長時監控
8~12GB
洩漏累積後
社群實測連跑一週不重啟
16GB+
主機商建議
偏保守

那為什麼還要在意記憶體?因為幻獸帕魯有個的老毛病:進程本身會隨時間慢慢變肥,跟你們在遊戲裡蓋了多少東西無關。社群實測一個 4 人服連續跑、都不重啟,一週內能從 5G 爬到 8~12G。所以真正該做的不是準備 32G,而是設一個 mem_limit 擋住上限、再配每天定時重啟(重啟會釋放記憶體,有人在線就延後),把洩漏壓在合理範圍——這樣它跑再久也不會拖垮同機的其他服務。

一份最小可用的 docker-compose#

核心設定其實不多。下面這份去掉了枝節,留下真正該懂的幾行:

yaml
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            # 遊戲本體 + 存檔都在這

幾個當下不明顯、之後會踩到的點:

  • 821127015 後面那個 /udp 不能漏。Palworld 走的是 UDP,漏了寫成 TCP,server 起得來、你本機也連得上,但外面的人一個都進不來。
  • RCON 綁 127.0.0.1:它是拿來讓自動備份/重啟能先廣播警告再優雅關機的管理通道,只給本機用,不該對外開。
  • mem_limitAUTO_REBOOT_ENABLED 是一組的,專門對付上面說的記憶體膨脹。

真正卡人的是網路:UDP 連線三關#

docker compose up -d 之後,server 就在 8211 上跑了,你自己在同一個網段連 區網IP:8211 通常沒問題。然後朋友一連,連不進來。

因為封包要從網際網路走到你家那個容器,中間有三道關,少一道就進不來:

主機防火牆放行 UDP

先讓封包進得了主機。 開兩個 UDP port:

bash
sudo ufw allow 8211/udp comment 'Palworld game'
sudo ufw allow 27015/udp comment 'Palworld query'

協定一定是 udp。這是三關裡最常被寫成 tcp 的一關。

路由器 port forwarding:外部 → 內網,而且是 UDP

封包從網際網路進到你家,要靠路由器把它轉發給那台主機。到路由器管理介面加兩條轉發規則:

外部 (WAN)→ 內部主機協定
8211192.168.x.x : 8211UDP
27015192.168.x.x : 27015UDP
讓朋友有個網址可以連:DDNS,而且是灰雲

家用網路的公網 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.ymlenvironment 區塊,讓它生成的時候就帶上你的值。常見的幾項:

常用的世界設定(寫進 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_FIREPvP / 友軍傷害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 更新:

bash
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. 記憶體別被嚇到:小團隊實測 1~2G 就夠(主機商的 16G 偏保守);真正要防的是記憶體洩漏,靠容器 mem_limit + 每日重啟壓住。
  2. compose:port 記得加 /udp;RCON 綁 127.0.0.1;密碼寫環境變數。
  3. 網路三關:ufw 放行 udp → 路由器 port forwarding(UDP!) → DDNS。
  4. Cloudflare 用灰雲,橘雲代理不轉 UDP,開了必連不上。
  5. 不用碰 nginx,UDP 遊戲封包不經過反向代理。
  6. 世界設定寫進 compose 的 environment,別手改 ini(會被重新生成蓋掉)。
  7. 朋友版本不符 = server 落後;比對 buildid,重啟容器觸發 SteamCMD 更新,更新前先 RCON 廣播 + 存檔。
  8. 備份排除遊戲本體(18GB),只單獨備份存檔目錄。
參考連結
  • thijsvanloef/palworld-server-docker —— 這篇用的 Docker 映像GitHub
  • Palworld 官方專用伺服器說明Palworld Wiki
  • Cloudflare —— 為什麼 Proxy(橘雲)只走 HTTP/HTTPSCloudflare Docs