All tutorials
14 min read

How to Host a Project Zomboid Dedicated Server on Ubuntu 24.04

Host a Project Zomboid dedicated server on Ubuntu 24.04 with SteamCMD and systemd: set the Java heap, open UDP 16261 and 16262, and back up the world.

TL;DR:

  • Install SteamCMD, download Steam app 380870 as an unprivileged zomboid user, and run the server under systemd, which sends save and quit to its console on stop.
  • Checked against Build 42.21, the stable public branch since September 28, 2026. The Linux server files take about 7.2 GB.
  • Players connect on UDP ports 16261 and 16262. The RCON port 27015 stays closed.
  • PZwiki, the official wiki, sizes the server heap at 3 GB plus about 500 MB per player. This tutorial starts at 8 GB of RAM with a 6 GB Java heap set in ProjectZomboid64.json.
  • Build 41 saves do not load on Build 42. The legacy41 branch keeps a Build 41 server running.

Applies to: Ubuntu 24.04 LTS · Project Zomboid Dedicated Server Build 42.21 · checked October 2026

A Project Zomboid dedicated server is The Indie Stone's free server program (Steam app 380870) that hosts a Project Zomboid multiplayer world without a game client running, so players can join while the host is offline. This tutorial installs the Build 42 server on Ubuntu 24.04 with SteamCMD, runs it under systemd as its own user, and covers the Java heap, servertest.ini, Workshop mods, admin commands, backups and updates per branch. A VPS keeps the world online when your own PC is off.

Project Zomboid dedicated server requirements

PZwiki, the official wiki, and The Indie Stone's release posts list:

ResourceGuidance
Server buildBuild 42.21 on the public (stable) branch. Build 41.78.21 on the legacy41 branch
RAMPZwiki: at least 3 GB for the server plus about 500 MB per player (4 players: 5 GB), more with mods. The Windows start script ships set to 16 GB
StorageAbout 7.2 GB of Linux server files, plus saves and backups
NetworkUDP 16261 (game port) and UDP 16262 (direct connection port)

The Java heap (-Xmx, with -Xms as its starting size) caps the memory for game data. The Java process uses some memory on top of it, so leave RAM free for it and for Ubuntu:

VPS RAMJava heap (-Xms and -Xmx)Players by PZwiki's sizing, no modsLeft outside the heap
8 GB6g62 GB
12 GB9g123 GB
16 GB12g184 GB

Move up a size for more players, many mods or memory errors. The Memory: line in systemctl status zomboid shows what the whole service uses.

Prerequisites

  • A VPS running Ubuntu 24.04 LTS with at least 8 GB RAM and your SSH public key added at deploy. Arct Cloud plans with 8 GB RAM and 4 vCPU are cvm.small, vm.tiny and the High Performance hvm.tiny; plans with 16 GB RAM and 8 vCPU are cvm.xlarge, vm.medium and hvm.medium.
  • An SSH key pair. See How to Generate an SSH Key on Windows, macOS, and Linux.
  • A non-root user with sudo privileges that logs in with your SSH key. The commands below create one.
  • A copy of Project Zomboid on Steam for each player, on the same branch as the server.

On a new server, log in as root and create the sudo user. The rsync line copies root's authorized SSH key to the new account, because the key added at deploy belongs to root:

adduser deploy
usermod -aG sudo deploy
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy

Open a second terminal and confirm ssh [email protected] works before you log out as root. Replace 203.0.113.10 with your server's public IP address. Commands below run as the sudo user. Replace values in capitals, such as YOUR_SERVER_NAME, with your own.

Step 1: Install SteamCMD

SteamCMD is Valve's command-line Steam client. Ubuntu ships it as a 32-bit package in the multiverse repository, so enable multiverse and the i386 architecture first. The SteamCMD tutorial covers the install in detail.

sudo apt update
sudo apt install -y software-properties-common
sudo add-apt-repository -y multiverse
sudo dpkg --add-architecture i386
sudo apt update

The package asks you to accept Valve's Steam License Agreement, which incorporates the Steam Subscriber Agreement. Read it, then record your answer and install:

echo steam steam/question select "I AGREE" | sudo debconf-set-selections
echo steam steam/license note '' | sudo debconf-set-selections
sudo apt install -y steamcmd

Step 2: Enable UFW and allow SSH

Allow SSH before you enable UFW, or UFW blocks your next SSH login:

sudo ufw allow OpenSSH
sudo ufw enable

Type y when UFW asks to confirm. The game ports stay closed until Step 10, after the join password is set.

Step 3: Create a system user for the server

PZwiki says not to run the server as root. Create an unprivileged service user that owns the server files and the world:

sudo useradd --system --create-home --home-dir /home/zomboid --shell /usr/sbin/nologin zomboid

Step 4: Get the Project Zomboid dedicated server for Linux

App ID 380870 is the Project Zomboid Dedicated Server tool. It downloads with an anonymous login, so no Steam account is needed on the server:

sudo -u zomboid -H /usr/games/steamcmd \
  +force_install_dir /home/zomboid/server \
  +login anonymous \
  +app_update 380870 validate \
  +quit

+force_install_dir must come before +login. The full /usr/games/steamcmd path is needed because sudo's default secure_path on Ubuntu does not include /usr/games. The output ends similar to this:

...
Success! App '380870' fully installed.

Step 5: Set the server memory

PZwiki documents ProjectZomboid64.json as the launcher's config file, with the heap size on its -Xmx line. A SteamCMD validate restores changed files, so this script sets the heap in the server folder's copy and the service runs it after every update. Create /usr/local/bin/zomboid-heap, with HEAP=6g changed to your row of the RAM table:

sudo tee /usr/local/bin/zomboid-heap > /dev/null <<'EOF'
#!/bin/sh
set -eu
HEAP=6g
CONF=/home/zomboid/server/ProjectZomboid64.json
sed -i -E "s/\"-Xm([sx])[0-9]+[gGmM]\"/\"-Xm\\1$HEAP\"/g" "$CONF"
grep -oE '"-Xm[sx][0-9]+[gGmM]"' "$CONF" || echo "No -Xmx entry found in $CONF"
EOF
sudo chmod 755 /usr/local/bin/zomboid-heap

The script also sets an -Xms entry if present, so the starting heap never exceeds the maximum. The service runs it at every start, so a later change to the HEAP= line applies at the next restart. Run it once as the service user:

sudo -u zomboid /usr/local/bin/zomboid-heap

The output shows the heap entries with the new value. PZwiki warns that the Windows script's shipped 16 GB setting must be changed or the server fails with memory errors, so set the heap before the first launch.

Step 6: Run the first launch and set the admin password

On the first run, the server asks for an admin password, then generates the world and settings files in /home/zomboid/Zomboid. PZwiki says to do this once by hand. -adminusername names the admin account; Step 9 uses the same name:

sudo -u zomboid -H bash -c 'cd /home/zomboid/server && bash start-server.sh -adminusername YOUR_ADMIN_NAME'

Use letters and numbers for the name and type the password when asked. When the console prints a line with SERVER STARTED, type quit and press Enter to save the world and stop.

Step 7: Configure servertest.ini settings

Set the server name, join password, player limit and autosave interval as the zomboid user:

sudo -u zomboid sed -i \
  -e 's/^PublicName=.*/PublicName=YOUR_SERVER_NAME/' \
  -e 's/^Password=.*/Password=YOUR_JOIN_PASSWORD/' \
  -e 's/^MaxPlayers=.*/MaxPlayers=6/' \
  -e 's/^SaveWorldEveryMinutes=.*/SaveWorldEveryMinutes=15/' \
  /home/zomboid/Zomboid/Server/servertest.ini

Use letters and numbers, because / and & break sed. MaxPlayers=6 matches the 6 GB heap in the RAM table. With the default SaveWorldEveryMinutes=0, PZwiki says the map is usually saved only when players leave an area. Check the values:

sudo grep -E '^(PublicName|Password|MaxPlayers|SaveWorldEveryMinutes|Public|Open|DefaultPort|UDPPort)=' \
  /home/zomboid/Zomboid/Server/servertest.ini

Other settings and their PZwiki defaults:

SettingDefaultEffect
Publicfalsetrue lists the server in the in-game browser
OpentruePlayers create an account on first join
DefaultPort / UDPPort16261 / 16262The two UDP ports
RCONPort / RCONPassword27015 / emptyRemote console; UFW keeps the port closed

Sandbox settings such as zombie population live in servertest_SandboxVars.lua. The server reads both files at its next start.

Step 8: Create the backup script

The service runs this script before every start, while the world is stopped, so each archive holds a consistent copy of the world, the settings and the server's db folder. Create /usr/local/bin/zomboid-backup:

sudo tee /usr/local/bin/zomboid-backup > /dev/null <<'EOF'
#!/bin/sh
set -eu
DATA=/home/zomboid/Zomboid
DEST=/home/zomboid/backups
[ -d "$DATA/Saves/Multiplayer" ] || exit 0
mkdir -p "$DEST"
find "$DEST" -name 'zomboid-*.tar.gz' -mmin -10 | grep -q . && exit 0
ITEMS="Saves/Multiplayer Server"
[ -d "$DATA/db" ] && ITEMS="$ITEMS db"
tar -czf "$DEST/zomboid-$(date +%Y%m%d-%H%M%S).tar.gz" -C "$DATA" $ITEMS
find "$DEST" -name 'zomboid-*.tar.gz' -mtime +14 -delete
EOF
sudo chmod 755 /usr/local/bin/zomboid-backup

The script skips the archive when one is less than 10 minutes old and keeps 14 days of archives.

Step 9: Run the server as a systemd service

PZwiki's systemd example connects the server console to a named pipe (FIFO) that systemd creates. On stop, the unit writes save, waits 15 seconds and writes quit. The same page warns that the developers discourage this method and that a clean save on shutdown is not guaranteed; Step 8 archives the world before each start.

Create /etc/systemd/system/zomboid.socket with sudo nano, paste this unit, then save with Ctrl+O and exit with Ctrl+X:

[Unit]
BindsTo=zomboid.service

[Socket]
ListenFIFO=/home/zomboid/zomboid.control
FileDescriptorName=control
RemoveOnStop=true
SocketMode=0660
SocketUser=zomboid

Create /etc/systemd/system/zomboid.service the same way. Replace YOUR_ADMIN_NAME with the name from Step 6:

[Unit]
Description=Project Zomboid Dedicated Server
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=zomboid
Group=zomboid
WorkingDirectory=/home/zomboid/server
Sockets=zomboid.socket
PrivateTmp=true
ExecStartPre=/usr/local/bin/zomboid-backup
ExecStartPre=-/usr/games/steamcmd +force_install_dir /home/zomboid/server +login anonymous +app_update 380870 +quit
ExecStartPre=/usr/local/bin/zomboid-heap
ExecStart=/bin/sh -c "exec /home/zomboid/server/start-server.sh -adminusername YOUR_ADMIN_NAME < /home/zomboid/zomboid.control"
ExecStop=/bin/sh -c "echo save > /home/zomboid/zomboid.control; sleep 15; echo quit > /home/zomboid/zomboid.control"
KillSignal=SIGCONT
TimeoutStartSec=1800
TimeoutStopSec=300

[Install]
WantedBy=multi-user.target

What the unit does:

  • Each start runs the backup, a SteamCMD update and the heap script. The - lets the server start when Steam is unreachable.
  • KillSignal=SIGCONT keeps systemd from killing the server after quit; it waits up to 5 minutes (TimeoutStopSec=300) for the save.
  • Like PZwiki's example, the unit has no automatic restart, so the pipe never holds a stale quit. After a crash or an in-game /quit, start it again.

Start the server and enable it at boot:

sudo systemctl daemon-reload
sudo systemctl enable --now zomboid
sudo systemctl status zomboid --no-pager

The Active: line reads active (running). Follow the log with sudo journalctl -u zomboid -f until a line with SERVER STARTED appears.

Step 10: Open UDP ports 16261 and 16262

Open the two UDP ports PZwiki lists, 16261 and the direct connection port 16262:

sudo ufw allow 16261:16262/udp
sudo ufw status

The output looks similar to this:

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
16261:16262/udp            ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
16261:16262/udp (v6)       ALLOW       Anywhere (v6)

If your provider runs a network firewall in front of the server, open the same ports there.

Step 11: Connect and verify the server

Check the UDP sockets and the console pipe:

sudo ss -ulpn | grep -E ':1626[12]'
echo players | sudo tee /home/zomboid/zomboid.control > /dev/null
sudo journalctl -u zomboid -n 10 --no-pager

ss lists the server's UDP sockets, including port 16261, and the journal shows the reply to players.

In Project Zomboid, select Join, open the Favorites tab and add the server's public IPv4 address (for example 203.0.113.10), port 16261, an account name and password, and the join password from Step 7. Save and join. For admin rights, log in as YOUR_ADMIN_NAME with the admin password.

Add Steam Workshop mods

servertest.ini lists mods in three lines: WorkshopItems= (Workshop IDs to download, separated by semicolons), Mods= (mod IDs to load) and Map= (map mods). The game's settings editor, which PZwiki documents, writes them for you:

  1. On your PC, subscribe to the mods, start Project Zomboid, select Host, then Manage Settings, and create or edit settings named servertest.
  2. Add the mods on the Steam Workshop and Mods pages, set the Map order for map mods, and save.
  3. Copy the three lines from servertest.ini in the Zomboid\Server folder of your PC user profile.

Paste them over the same lines on the server while the service is stopped:

sudo systemctl stop zomboid
sudo -u zomboid nano /home/zomboid/Zomboid/Server/servertest.ini
sudo systemctl start zomboid

The server downloads the Workshop items as it starts, and players get them on connect. PZwiki notes that mods for older versions are likely not to work, so a Build 41 mod needs an update from its author. Add mods you trust: in April 2026, The Indie Stone reported 14 Workshop mods that created malicious files outside the game folder, and they were removed from the Steam Workshop.

Project Zomboid server commands

Admin commands work in the server console and in game chat, where each starts with /. From PZwiki's command list:

CommandEffect
playersList connected players
saveSave the world
servermsg "text"Broadcast a message
kickuser "name"Kick a player
banuser "name" -ipBan a player and the player's IP address
setaccesslevel "name" "moderator"Set Admin, Moderator, Overseer, GM, Observer or none
checkModsNeedUpdateWrite to the log whether a mod has an update

From SSH, write a command to the console pipe and read the reply in the journal:

echo 'servermsg "Restart in 5 minutes"' | sudo tee /home/zomboid/zomboid.control > /dev/null
sudo journalctl -u zomboid -n 5 --no-pager

Update the Project Zomboid server and switch branches

Each restart checks Steam for a new build on the server's branch, so sudo systemctl restart zomboid applies an update. Build 42.21 fixed a way into dedicated servers without Steam authentication that broke SteamID bans, so update after each stable release. To verify every file, run the download with validate while the server is stopped:

sudo systemctl stop zomboid
sudo -u zomboid -H /usr/games/steamcmd \
  +force_install_dir /home/zomboid/server \
  +login anonymous \
  +app_update 380870 validate \
  +quit
sudo systemctl start zomboid

Branches of app 380870 on October 6, 2026:

BranchBuildSteamCMD option
publicBuild 42.21, stablenone
unstableNew builds before they reach stable-beta unstable
legacy41Build 41.78.21-beta legacy41
42.19Build 42.19.2-beta 42.19

Valve's SteamCMD guide says the -beta option must be quoted on the command line. To switch to legacy41, stop the server, archive the world with the Step 8 script, then run the download with the branch inside the quotes:

sudo systemctl stop zomboid
sudo -u zomboid /usr/local/bin/zomboid-backup
sudo -u zomboid -H /usr/games/steamcmd \
  +force_install_dir /home/zomboid/server \
  +login anonymous \
  +app_update "380870 -beta legacy41 validate" \
  +quit

Open the unit with sudo nano /etc/systemd/system/zomboid.service and change the update line to:

ExecStartPre=-/usr/games/steamcmd +force_install_dir /home/zomboid/server +login anonymous +app_update "380870 -beta legacy41" +quit

Apply the change and start the server:

sudo systemctl daemon-reload
sudo systemctl start zomboid

Use -beta public the same way to move back to the stable branch. Players pick the same branch under Properties, Game Versions & Betas in Steam.

Back up and restore the world

Every start writes an archive to /home/zomboid/backups. The server also keeps its own backups, set by BackupsCount (default 5), BackupsOnStart and BackupsOnVersionChange in servertest.ini. List the archives:

sudo ls -lh /home/zomboid/backups

To restore one, stop the server, move the current world aside and extract the archive, which also restores the settings and db folder. Replace YYYYMMDD-HHMMSS with its timestamp:

sudo systemctl stop zomboid
sudo -u zomboid mv /home/zomboid/Zomboid/Saves/Multiplayer /home/zomboid/Zomboid/Saves/Multiplayer.old-$(date +%Y%m%d-%H%M%S)
sudo -u zomboid tar -xzf /home/zomboid/backups/zomboid-YYYYMMDD-HHMMSS.tar.gz -C /home/zomboid/Zomboid
sudo systemctl start zomboid

The archives share a disk with the world. Copy them to your computer as shown in how to copy files to a VPS. For copies kept off the server, see VPS backups.

Troubleshoot common Project Zomboid server errors

SymptomCauseFix
Joining times out or the server failed to respondServer down, UDP ports blocked, or a different branchCheck systemctl status zomboid, sudo ufw status and the branch in Steam
Assertion Failed: Illegal termination of worker threadData from an earlier Build 41 serverRun sudo cat /home/zomboid/server/steam_appid.txt; it must hold only 108600. Then back up and move /home/zomboid/Zomboid aside
Server terminated at startup, OutOfMemoryError or killed by the OOM killer in the journalHeap too large for free RAM, or too small for the worldRun sudo sed -i 's/^HEAP=.*/HEAP=9g/' /usr/local/bin/zomboid-heap with your row of the RAM table, then sudo systemctl restart zomboid, or add RAM
Journal stops at the admin password promptStep 6 skipped, or another -adminusername in the unitStop the service and run Step 6 with the same name
Settings not saving, or servertest.ini changes do nothingEdited a copy the server does not readEdit /home/zomboid/Zomboid/Server/servertest.ini as zomboid, then run reloadoptions or restart

FAQ

How much RAM does a Project Zomboid dedicated server need?

PZwiki, the official wiki, says to assign the server at least 3 GB plus about 500 MB per player, so 2 players need 4 GB and 4 players need 5 GB. This tutorial sets a 6 GB Java heap on a server with 8 GB of RAM. Mods need more.

Is a Project Zomboid dedicated server free?

Yes. The server tool, Steam app 380870, downloads free with an anonymous SteamCMD login. Each player still needs a copy of Project Zomboid on the same branch as the server.

Can you host a Project Zomboid server without playing?

Yes. The dedicated server runs without a game client, so the world stays online while you are offline. You join from your own PC like any other player.

Can you make a private server in Project Zomboid?

Yes. Set Password in servertest.ini so players need it to join; Steam's server browser lists Steam servers anyway, so the password keeps it private. Public=false keeps it out of the in-game list, and Open=false with the adduser command makes it invite-only.

How do I make a server in Project Zomboid Build 42?

Install Steam app 380870 from the public branch, which has carried Build 42 since July 29, 2026. Build 41 saves do not load on Build 42, so to keep a Build 41 world, install the server from the legacy41 branch and have players switch the game to legacy41 in Steam.

How do I join a dedicated server in Project Zomboid?

Select Join, open the Favorites tab and add the server's public IPv4 address, port 16261, an account name and password, and the join password. Save the entry and join. Your VPS provider shows the IP address.

Next steps

High Performance plans run on AMD Ryzen 9 up to 5.7 GHz or AMD EPYC Genoa 9004 Series up to 4.3 GHz, with DDR5 RAM. Compare plans.

This work is licensed under CC BY-NC-SA 4.0.