Skip to content

jasdian/zomboid-seasons

Repository files navigation

Zomboid Seasons

Seasonal Project Zomboid server with Ethereum payment integration. Pay ETH to register, get whitelisted immediately. 90-day season rotation — top zombie killers earn free entry to the next season.

Requires Build 42+ (currently running unstable until Build 42 reaches stable).

Quick Start

nix-shell
cargo run -- test-config.toml

Architecture

Internet -> Caddy/Nginx (TLS) -> zomboid-seasons :3000 -> RCON -> PZ Server
  • Backend (zomboid-seasons container): Rust/Axum on port 3000
  • PZ Server (zomboid.service): Project Zomboid Build 42+ dedicated server via SteamCMD
  • Database: SQLite with WAL mode

Build

# Development
cargo build && cargo run

# Production (static MUSL binary)
cargo build --release --no-default-features --target x86_64-unknown-linux-musl

Configuration

Copy config.prod.toml and fill in:

  • ETH RPC URL and deposit address
  • RCON password file path
  • Admin bearer token
  • PZ server name and paths

Deployment

All scripts run locally and execute commands on the remote server via SSH.

First-time setup (in order)

# 0. Copy .env.example to .env and fill in server details
cp .env.example .env

# 1. Create pzuser, directories, firewall rules
./scripts/setup-server.sh

# 2. Create RCON password on server
source .env && ssh -p $DEPLOY_SSH_PORT $DEPLOY_SERVER 'openssl rand -hex 16 > /root/zomboid-seasons/rcon.pw'

# 3. Install PZ dedicated server via SteamCMD (unstable branch by default, requires Steam login)
./scripts/sync-zomboid.sh your_steam_username

# 4. Create systemd service with RCON
./scripts/setup-zomboid-service.sh

# 5. Deploy the Rust backend (Docker)
./scripts/deploy.sh

Updating

# Update PZ server (stops service, updates via SteamCMD, restarts)
./scripts/sync-zomboid.sh your_steam_username

# Redeploy backend (builds binary, copies to server, restarts container)
./scripts/deploy.sh

Scripts

Script Purpose When to run
setup-server.sh Create pzuser, directories, UFW rules Once, on fresh server
sync-zomboid.sh Install/update PZ server via SteamCMD (unstable branch by default) Initial setup + game updates
setup-zomboid-service.sh Create systemd unit, configure RCON Once, after first sync
deploy.sh Build and deploy Rust backend (Docker) Every backend release
deploy.sh --mod-only Rsync Lua mod + hot-reload via RCON (no restart) Lua-only changes
restart-pz.sh Restart PZ game server via systemctl After .ini/sandbox changes
switch-branch.sh Switch PZ branch (wipes saves, reinstalls, redeploys) When Build 42 hits stable (switch from unstable to public)
backup.sh Backup SQLite DB and config Runs daily via cron (set up by deploy.sh)

PZ Server Configuration

Directory structure

/home/pzuser/
  pzserver/                                PZ dedicated server (installed via apt steamcmd)
  Zomboid/
    mods/
      ZomboidSeasons/                      Server-side only Lua mod (kill tracking, events)
        42/                                Build 42 copy (required by B42 mod loader)
    Server/
      zomboid-seasons.ini                  Main server config
      zomboid-seasons_SandboxVars.lua      Gameplay tuning
    Saves/
      Multiplayer/
        zomboid-seasons/                   World save data (wiped on rotation)
    ZomboidSeasons/                        Mod runtime data (kills.json, drops, config)

Key server.ini settings

Setting Description
PublicName= Server name in browser (managed by season rotation)
PublicDescription= Server description
MaxPlayers= Player cap
PVP=true/false PvP toggle
Open=false Whitelist mode: only adduser accounts can join (managed by backend)
AutoCreateUserInWhiteList=false Prevent players from self-registering accounts (managed by backend)
Password= Join password (empty = no password)
PauseEmpty=true Pause when no players connected
Map=Muldraugh, KY Map name
DefaultPort=16261 Game port (UDP)
RCONPort=27016 RCON port (set by setup-zomboid-service.sh)
RCONPassword= RCON password (set by setup-zomboid-service.sh)

Adding mods

Two fields in zomboid-seasons.ini must be kept in sync (semicolon-separated):

WorkshopItems=steamId1;steamId2;steamId3
Mods=modId1;modId2;modId3
  • WorkshopItems = numeric Steam Workshop IDs (from the mod's Steam URL)
  • Mods = string mod IDs (from each mod's mod.info file)
  • Server auto-downloads workshop mods on start; clients download when connecting
  • Restart the server after changing mods

Sandbox settings

File: /home/pzuser/Zomboid/Server/zomboid-seasons_SandboxVars.lua

Controls gameplay mechanics: zombie population, loot respawn, day length, erosion speed, infection settings, etc. Generated on first server start with defaults. Edit while server is stopped. Delete the file to reset to defaults.

Promoting a user to admin

Admin / moderator privileges are managed through PZ's RCON, not through the backend. The user must already exist in PZ's user DB (added via adduser — the backend does this automatically once a registration is confirmed).

# Grant admin (full powers: god mode, teleport, item spawn, ban/kick, etc.)
./scripts/rcon.sh 'setaccesslevel "USERNAME" "admin"'

# Other roles (lower privilege, in descending order):
./scripts/rcon.sh 'setaccesslevel "USERNAME" "moderator"'   # kick/ban, teleport, no item spawn
./scripts/rcon.sh 'setaccesslevel "USERNAME" "overseer"'    # observer + light moderation
./scripts/rcon.sh 'setaccesslevel "USERNAME" "gm"'          # god mode + spawn, no admin UI
./scripts/rcon.sh 'setaccesslevel "USERNAME" "observer"'    # spectator/noclip only

# Demote back to a regular player:
./scripts/rcon.sh 'setaccesslevel "USERNAME" "none"'

Successful response: User USERNAME is now admin. Username is case-sensitive and must match exactly what's in registrations.zomboid_username.

The access level is stored in PZ's user DB (~/Zomboid/db/<server_name>.db), which lives outside the save directory. Season rotation only wipes saves, so admin level survives rotation as long as the username carries forward (top-3 killers do automatically; everyone else has to re-register and pay, then be re-promoted).

DNS

Two types of DNS records are needed:

A record — points the domain to the server IP, used by the web backend (reverse proxy with TLS):

zomboid.princeofcrypto.com.  A  <SERVER_IP>

SRV record — allows game clients to discover the server by domain name and port:

_zomboid._udp.zomboid.princeofcrypto.com.  SRV  0 0 16261 zomboid.princeofcrypto.com.

Players connect using the domain name; the SRV record resolves the correct port.

Ports

Port Protocol Purpose
16261 UDP Game traffic
16262 UDP+TCP Steam query
27016 TCP RCON (Docker-only, not exposed externally)
3000 TCP Backend API (behind reverse proxy)

Firewall (UFW)

Configured by setup-server.sh:

22499/tcp    SSH
80/tcp       HTTP (reverse proxy)
443/tcp      HTTPS (reverse proxy)
16261/udp    PZ game port
16262         PZ Steam query port (UDP+TCP)
27016/tcp    RCON (restricted to Docker subnet 172.16.0.0/12)

Troubleshooting

PZ server auto-shuts down immediately after starting

Symptom: systemctl status zomboid.service shows the server starts, runs for a few seconds, then quits. Logs show:

command entered via server console (System.in): "save"
command entered via server console (System.in): "quit"

Cause: The PZ server reads stdin from a FIFO pipe (/home/pzuser/pzserver/zomboid.control). When a previous ExecStop wrote save and quit to the FIFO but the server had already exited (crash, manual kill, etc.), those commands remain buffered in the pipe. On next start, the server reads the stale commands and immediately shuts down. This creates a restart loop since Restart=on-failure keeps restarting into the same stale FIFO.

Fix: Flush the FIFO by stopping everything, deleting it, and restarting:

systemctl stop zomboid.service
systemctl stop zomboid.socket
rm -f /home/pzuser/pzserver/zomboid.control
systemctl start zomboid.socket
systemctl start zomboid.service

About

Project Zomboid server with whitelist managed by Rust backend. Includes STATUS binary, that is standalone monitoring project.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors