Short answer: a Project Zomboid dedicated server is the free Project Zomboid Dedicated Server tool, SteamCMD app 380870. On Linux you install it with SteamCMD, open UDP 16261 and 16262 (UDP only), set the Java heap with -Xmx in ProjectZomboid64.json, start start-server.sh once by hand to set the admin password, and then run it under systemd. Settings and mods live in ~/Zomboid/Server/servertest.ini. The default Steam branch is Build 42; Build 41 stays available as legacy41.
| Item | Value | Note |
|---|---|---|
| SteamCMD app ID | 380870 | Anonymous login; -beta legacy41 for Build 41 |
| Game ports | UDP 16261 and 16262 | DefaultPort and UDPPort in servertest.ini |
| RCON | TCP 27015 | Only for remote admin tools; keep it closed |
| Memory | -Xmx | vmArgs in ProjectZomboid64.json |
| Settings | ~/Zomboid/Server/servertest.ini | Plus SandboxVars, spawn points and regions |
| World | ~/Zomboid/Saves/Multiplayer/servertest | Renamed with -servername |
| Player limit | 32 by default | MaxPlayers; above 32 risks desync |
How much RAM does a Project Zomboid server need?
Project Zomboid runs on Java, so RAM comes in two parts. The heap, capped by -Xmx, holds the game world. Next to it Java uses off-heap memory that -Xmx does not limit, and that part grows with players and with the map cells they keep loaded. A heap set to the full RAM of the machine therefore ends with the kernel killing the server. Leave room:
| Server | VPS RAM | Heap (-Xmx) | Why |
|---|---|---|---|
| 2 to 6 players, vanilla | 8 GB | -Xmx5g | About 3 GB left for off-heap memory and the OS |
| 6 to 16 players, a few mods | 12 to 16 GB | -Xmx8g to -Xmx10g | Mods add items, maps and Lua to the heap |
| 16+ players or a long mod list | 16 GB and up | RAM minus 4 to 6 GB | Off-heap use rises with every loaded area |
These are starting points, not official figures. Watch free -h with your group online and adjust. For CPU, the game loop sits on a few busy threads while Java’s garbage collector works alongside it, so fast cores and at least four vCores keep the two from competing. VMHeaven’s Hi-CPU KVM (AMD EPYC, ECC memory) is built for that pattern; Standard KVM fits better if you want many cores for several servers on one box. To size Project Zomboid against eight other games on both lines, see gaming VPS.
How do I install the server with SteamCMD?
- 1Create a user and the install folder
Do not run the server as root. This user gets a normal shell because the first start is interactive:
Debian · Ubuntu sudo useradd --create-home --shell /bin/bash pzuser sudo install -d -o pzuser -g pzuser /opt/pzserver - 2Install SteamCMD
SteamCMD needs the i386 architecture and comes from Ubuntu’s
multiverseor Debian’snon-freecomponent. Accept the Steam licence when asked.Ubuntu 24.04 sudo add-apt-repository -y multiverse sudo dpkg --add-architecture i386 sudo apt update && sudo apt install -y steamcmdDebian 12 · 13 sudo dpkg --add-architecture i386 # skip the file if your sources already include non-free sudo tee /etc/apt/sources.list.d/non-free.sources >/dev/null <<EOF Types: deb URIs: http://deb.debian.org/debian Suites: $(. /etc/os-release && echo "$VERSION_CODENAME") Components: non-free Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg EOF sudo apt update && sudo apt install -y steamcmd - 3Download app 380870
Debian · Ubuntu sudo -u pzuser -H /usr/games/steamcmd \ +force_install_dir /opt/pzserver \ +login anonymous +app_update 380870 validate +quit # Build 41 instead (players must run Build 41 too): # +app_update 380870 -beta legacy41 validateThe game client and the server must be on the same build. Run the same command to update, and update both sides together.
How do I set -Xmx in ProjectZomboid64.json?
On Linux, start-server.sh launches ProjectZomboid64, which reads its Java options from the vmArgs list in /opt/pzserver/ProjectZomboid64.json. Find the current values first:
grep -n -E '"-Xm[sx]' /opt/pzserver/ProjectZomboid64.jsonChange the -Xmx entry to the heap you chose, for example "-Xmx8g",. If there is an -Xms entry as well, keep it at or below the -Xmx value: Java refuses to start when the initial heap is larger than the maximum. Every entry except the last needs a trailing comma, and one missing comma stops the server from starting, so check the file afterwards:
sudo -u pzuser nano /opt/pzserver/ProjectZomboid64.json
python3 -m json.tool /opt/pzserver/ProjectZomboid64.json >/dev/null && echo "JSON OK"How do I set the admin password on the first run?
There is no admin password until you create one. On the very first start the server asks for a password for its built-in admin account, so that start has to happen in a terminal:
sudo -u pzuser -i
cd /opt/pzserver
./start-server.sh -servername servertest
# enter the admin password when asked, wait until the server reports it has started,
# then type: quit
exitThat run also creates ~/Zomboid/Server/servertest.ini, the sandbox and spawn files, and the world. -servername picks which set of files is used; another name gives you a separate world with its own settings. There is also an -adminpassword start option, but it leaves the password in your shell history and the process list, so use it once at most and never put it in a unit file.
Which ports does a Project Zomboid server need?
Two UDP ports: DefaultPort 16261 and UDPPort 16262. Both are UDP, so a TCP rule for them does nothing. RCON on TCP 27015 is for remote admin tools; leave it closed and use it over SSH if you need it.
sudo ufw allow 16261/udp comment 'Project Zomboid'
sudo ufw allow 16262/udp comment 'Project Zomboid'
sudo ufw status
# with the server running:
sudo ss -ulpn | grep -E ':1626[12]\b'A second server on the same machine needs its own pair of UDP ports, set in its own INI file. If ufw is not active yet, allow SSH before you enable it; the UFW setup guide has the safe order.
Which servertest.ini settings matter?
servertest.ini holds the server rules; the gameplay sandbox is in servertest_SandboxVars.lua next to it. You can edit the INI while the server runs and apply it with the admin command reloadoptions. The lines most people change first:
PublicName=Our Zomboid server
Public=false
Password=friends-only
MaxPlayers=16
Open=true
PVP=false
SaveWorldEveryMinutes=15
BackupsOnStart=true
BackupsPeriod=0
BackupsCount=5
RCONPassword=| Setting | Default | What it does |
|---|---|---|
| Public | false | true lists the server in the in-game browser |
| Password | empty | Empty means anyone with the IP can join |
| MaxPlayers | 32 | Admins do not count; above 32 risks map streaming and desync |
| Open | true | false allows only accounts an admin created |
| SaveWorldEveryMinutes | 0 | 0 saves an area only when players leave it; 10 to 15 limits what a crash can cost |
| BackupsOnStart / BackupsPeriod / BackupsCount | true / 0 / 5 | The server's own rolling backups, on the same disk |
| RCONPassword | empty | Leave empty unless you use an RCON tool |
How do I add mods?
A Workshop mod needs two entries. WorkshopItems= lists the Workshop IDs, the number in the mod’s Workshop URL, separated by semicolons; the server downloads those at start. Mods= lists the mod IDs from each mod’s mod.info, also separated by semicolons, in load order. On Build 42 each mod ID is written with a leading backslash; on Build 41 it is the bare ID:
WorkshopItems=1111111111;2222222222
Mods=\ExampleModA;\ExampleModB- One Workshop item can hold several mods. Its ID goes into
WorkshopItemsonce, but each mod ID you want active goes intoMods. - Map mods also need their map folder name in
Map=, placed before the defaultMuldraugh, KY. - Let the game write the lines if in doubt. In the client, Host, then Manage Settings, lets you pick mods in a menu. Compare the INI it saves with yours.
- Restart the server after changing mods. Players download the same mods automatically when they connect.
How do I run it as a systemd service?
The server reads commands from its console, so the trick is to give it a console that systemd controls. Be aware that the PZwiki says the developers discourage running the server under systemd and that a clean save on shutdown is not guaranteed. The setup below keeps the risk low: it sends save and then quit through a named pipe (FIFO) and waits for Java to exit, instead of killing it. Run the interactive first start above before you set this up.
[Unit]
Description=Project Zomboid console pipe
BindsTo=zomboid.service
[Socket]
ListenFIFO=/opt/pzserver/zomboid.control
FileDescriptorName=control
RemoveOnStop=true
SocketMode=0660
SocketUser=pzuser[Unit]
Description=Project Zomboid dedicated server
Requires=zomboid.socket
Wants=network-online.target
After=network-online.target zomboid.socket
[Service]
Type=simple
User=pzuser
Group=pzuser
WorkingDirectory=/opt/pzserver
Sockets=zomboid.socket
# re-apply your heap (use your own -Xmx; -Xms must not exceed it) in case an update restored the file
ExecStartPre=/usr/bin/sed -i -E -e 's/"-Xmx[0-9]+[mMgG]"/"-Xmx8g"/' -e 's/"-Xms[0-9]+[mMgG]"/"-Xms1g"/' /opt/pzserver/ProjectZomboid64.json
# the server reads its console from the pipe
ExecStart=/bin/sh -c 'exec /opt/pzserver/start-server.sh -servername servertest < /opt/pzserver/zomboid.control'
# save, quit, then wait until Java has exited
ExecStop=/bin/sh -c 'echo save > /opt/pzserver/zomboid.control; sleep 15; echo quit > /opt/pzserver/zomboid.control; while kill -0 $MAINPID 2>/dev/null; do sleep 1; done'
# a harmless signal, so systemd does not kill Java before it has saved
KillSignal=SIGCONT
TimeoutStopSec=180
# start-server.sh exits with 0 even after a crash, so on-failure would never fire
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now zomboid
sudo journalctl -u zomboid -f
# send any console command through the pipe, then read the answer in the journal
echo "players" | sudo tee /opt/pzserver/zomboid.control >/dev/nullBecause of Restart=always, a quit typed in the console brings the server straight back; use systemctl stop when you want it to stay down. Before you rely on the stop, run sudo systemctl stop zomboid once and check the journal for the save. The background on unit files, restart policies and journalctl is in creating a systemd service.
Where is the world, and how do I back it up?
Everything the server writes sits in /home/pzuser/Zomboid: the world in Saves/Multiplayer/servertest, the settings in Server, and the player accounts in db. With BackupsOnStart the server keeps a few copies of its own, but those stay on the same disk. For a copy you can move off the machine, save first and then archive:
#!/bin/bash
set -euo pipefail
CTL=/opt/pzserver/zomboid.control
DEST=/home/pzuser/backups
mkdir -p "$DEST"
# ask the running server to save; skip if it is not running
if [ -p "$CTL" ]; then echo save > "$CTL"; sleep 30; fi
# exit code 1 only means a file changed while it was read; the archive is still usable
tar -czf "$DEST/zomboid-$(date +%F-%H%M).tar.gz" -C /home/pzuser Zomboid || [ $? -eq 1 ]
# keep 7 days of archives
find "$DEST" -name 'zomboid-*.tar.gz' -mtime +7 -deletesudo -u pzuser nano /home/pzuser/backup.sh # paste the script above
sudo chown pzuser:pzuser /home/pzuser/backup.sh && sudo chmod 750 /home/pzuser/backup.sh
sudo crontab -u pzuser -e
# add: 45 4 * * * /home/pzuser/backup.shThe -p test matters: it only writes to the pipe while it exists, so a backup never leaves a plain file behind that would stop the socket from starting. On a VMHeaven VPS the panel can also back up the whole server, by hand or on a schedule, and its browser VNC console reaches the machine even when SSH does not.
Why can’t players connect? Common problems, most likely first
1. Players time out or hang while connecting
Check that both UDP ports are open, not TCP, and that the server listens (the ss line above). Players add the server under Join, then Favorites, with your public IP and port 16261.
2. Version mismatch
The client and server builds differ, usually Build 41 against Build 42. Install the server on the branch your players use, or have them switch in Steam under the game’s Betas tab.
3. Out of memory
Two different failures look alike. java.lang.OutOfMemoryError in the journal means the heap is too small: raise -Xmx. A server that vanishes with Killed process in sudo journalctl -k means heap plus off-heap outgrew the machine: lower -Xmx or add RAM. More on the second case in processes killed when memory runs out.
4. The server will not start after a JSON edit
A comma is missing or doubled in vmArgs. Run the json.tool check above; it names the line.
5. Mods do not load, or players are kicked for mismatching files
Check the backslash syntax on Build 42 and that every mod ID in Mods belongs to an item in WorkshopItems. If Windows players are still kicked with matching mods, DoLuaChecksum=true may be the cause: on a modded Linux server it is a known source of false mismatches, because Linux and Windows can list the mod files in a different order before hashing them. Turn it off only after you have ruled out real differences, because the check exists to stop modified clients.
6. Illegal termination of worker thread after moving to Build 42
Old Build 41 data in ~/Zomboid trips up the new build. Stop the server, rename the folder rather than deleting it (mv ~/Zomboid ~/Zomboid.b41 as pzuser), start once by hand to recreate it, then copy back only the settings you need. The wiki also asks you to check that steam_appid.txt in the server folder contains only 108600.
For the same SteamCMD and systemd pattern with a telnet console instead of a pipe, see the 7 Days to Die server guide.
Frequently asked
What ports does a Project Zomboid dedicated server use?
UDP 16261 (DefaultPort) and UDP 16262 (UDPPort). Both are UDP, so a TCP rule for them does nothing, and the RCON port, TCP 27015, should stay closed to the internet.
How do I give a Project Zomboid server more RAM on Linux?
Change the -Xmx entry in the vmArgs list of ProjectZomboid64.json in the server folder, for example to "-Xmx8g", and restart. Leave a few gigabytes of the machine's RAM outside the heap for Java's off-heap memory and the operating system, and re-apply the change after updates, which can restore the default file.
What is the admin password on a Project Zomboid dedicated server?
There is none until you set it: on the first start, start-server.sh asks you to choose a password for the built-in admin account. Run that first start by hand in a terminal, then log in from the game with the username admin and that password.