Hosting Guides

Optimizing Project Zomboid Memory and UDP Ports via LinuxGSM

8 min readUbuntu 24.04LinuxGSMJava
Once your server is online, jump to the Project Zomboid command and config reference.

Project Zomboid runs on a custom Java engine that, while charming, has a famously aggressive memory footprint once a horde event spawns several thousand active zombies inside loaded cells. The default 2 GB heap will stall the world thread within minutes. This guide stands up a hardened LinuxGSM deployment on Ubuntu 24.04, opens both required UDP ports, and tunes the G1 garbage collector to absorb sustained horde pressure without pauses long enough to drop client connections.

Prerequisites

  • Ubuntu 24.04 LTS with at least 8 GB of RAM and a 4 core CPU.
  • A non root user with sudo access (LinuxGSM refuses to run as root).
  • UDP 16261 (game) and UDP 16262 (steam channel) open at the firewall.
  • At least 20 GB of free disk for the SteamCMD download and persistent saves.

Step 1: System Preparation

user@host
sudo adduser --disabled-password --gecos "" pzuser
sudo dpkg --add-architecture i386
sudo apt update
sudo apt install -y curl wget file tar bzip2 gzip unzip bsdmainutils \
python3 util-linux ca-certificates binutils bc jq tmux netcat-openbsd \
lib32gcc-s1 lib32stdc++6 libsdl2-2.0-0:i386 openjdk-17-jre-headless

Step 2: Install LinuxGSM and the Server

user@host
sudo machinectl shell pzuser@
cd ~
wget -O linuxgsm.sh https://linuxgsm.sh
chmod +x linuxgsm.sh
bash linuxgsm.sh pzserver
./pzserver install

Step 3: Open the Dual UDP Ports

Zomboid uses two UDP ports, and a common misconfiguration is to forward only 16261. Without 16262 open, the steam channel handshake fails and clients hang on the connecting screen with no log line on the server side.

user@host
sudo ufw allow 16261/udp
sudo ufw allow 16262/udp
sudo ufw reload

Step 4: Tune the JVM for Horde Events

Edit the JVM arguments file to switch from the default parallel collector to G1, raise the heap to a host appropriate ceiling, and pin MaxGCPauseMillis low enough that the game loop never stalls past a tick.

~/lgsm/config-lgsm/pzserver/pzserver.cfg
startparameters="-Xms6g -Xmx6g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=50 \
-XX:+ParallelRefProcEnabled \
-XX:+AlwaysPreTouch \
-XX:+UnlockExperimentalVMOptions \
-Dzomboid.steamport=16261 \
-Dzomboid.znetlog=1 \
-- -cachedir=/home/pzuser/Zomboid"

Step 5: Automated World Saves

user@host
crontab -e
0 */2 * * * /home/pzuser/pzserver send "save"
30 4 * * * /home/pzuser/pzserver send "quit"
35 4 * * * /home/pzuser/pzserver start

Performance and Tuning

  • Match -Xms and -Xmx to lock the heap and avoid resize pauses.
  • Leave at least 1.5 GB of host RAM headroom outside the JVM for the OS page cache.
  • Lower MaxGCPauseMillis below 50 only if you are also seeing player rubber banding, not because lower looks better.

Conclusion

A correctly tuned Zomboid server with both UDP ports exposed, a G1 garbage collector tuned for tight pauses, and a cron driven save loop will survive the worst horde events your community can engineer.