#!/bin/bash # panel-native DayZ entrypoint. # # Contract: # /game — SteamCMD-installed DayZ Server (app 223350). Populated # by the panel's SteamCMD updater sidecar, which uses the # operator-supplied Steam credentials (the module manifest # sets requires_steam_login: true). # /game-saves — serverDZ.cfg + profiles/ (logs, bans, RPTs) + optional # mpmissions/ override tree. set -euo pipefail log() { printf '[panel-dayz] %s\n' "$*"; } # ----- stage 1: root-only bootstrap ----- if [[ "$(id -u)" = "0" ]]; then chown -R panel:panel /game /game-saves /home/panel 2>/dev/null || true log "dropping privileges to panel (UID 1000)" exec setpriv --reuid=panel --regid=panel --clear-groups \ --inh-caps=-all --bounding-set=-all \ env \ HOME=/home/panel \ SERVER_NAME="${SERVER_NAME:-panel DayZ}" \ SERVER_PORT="${SERVER_PORT:-2302}" \ SERVER_PASSWORD="${SERVER_PASSWORD:-}" \ BE_PASSWORD="${BE_PASSWORD:-panel_be}" \ CPU_COUNT="${CPU_COUNT:-2}" \ LD_LIBRARY_PATH="/game:${LD_LIBRARY_PATH:-}" \ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \ /entrypoint.sh "$@" fi GAME_DIR=/game SAVE_DIR=/game-saves DEDI_EXE="${GAME_DIR}/DayZServer" if [[ ! -x "${DEDI_EXE}" ]]; then log "ERROR: ${DEDI_EXE} not found or not executable." log " Run 'Update' on this server in the panel — the modal will" log " prompt for Steam credentials (DayZ is paid content; the" log " anonymous SteamCMD login won't work)." exit 78 # EX_CONFIG fi # --- persist profiles into /game-saves --- # DayZ writes RPT crash logs, ADM admin logs, and BattlEye bans to # /profiles/. Move out to the save volume + symlink back on # first boot so SteamCMD validate can't wipe them. mkdir -p "${SAVE_DIR}/profiles" if [[ -d "${GAME_DIR}/profiles" && ! -L "${GAME_DIR}/profiles" ]]; then mv "${GAME_DIR}/profiles"/* "${SAVE_DIR}/profiles/" 2>/dev/null || true rm -rf "${GAME_DIR}/profiles" fi ln -sfn "${SAVE_DIR}/profiles" "${GAME_DIR}/profiles" # --- seed serverDZ.cfg on first boot --- CFG="${SAVE_DIR}/serverDZ.cfg" if [[ ! -s "${CFG}" ]]; then log "seeding serverDZ.cfg (first boot)" cat > "${CFG}" <.cfg` # files BE writes after first handshake — if the password has changed, the # active copy will mismatch and BE refuses incoming RCON packets. # # Reference: AMP's dayz-experimental.kvp uses `{{$FullBaseDir}}battleye` as # the BE path and their PreStartStages purge the active file the same way. BE_DIR="${GAME_DIR}/battleye" for CFGPATH in "${BE_DIR}/beserver_x64.cfg" "${BE_DIR}/battleye/beserver_x64.cfg"; do if [[ -d "$(dirname "${CFGPATH}")" ]]; then log "writing ${CFGPATH} (RCON port 2305, pw from BE_PASSWORD)" cat > "${CFGPATH}" </dev/null || true rm -f "${BE_DIR}/battleye/beserver_x64_active_"*.cfg 2>/dev/null || true cd "${GAME_DIR}" log "starting DayZ dedicated server" log " name: ${SERVER_NAME}" log " game port: ${SERVER_PORT}/udp" log " rcon port: 2305/udp (internal, BattlEye)" log " cfg: ${CFG}" trap 'log "SIGTERM received"; kill -TERM "${DZ_PID:-0}" 2>/dev/null || true; wait "${DZ_PID:-0}" 2>/dev/null || true; exit 0' TERM INT # --- mod list dynamic build --- # Panel's mod manager maintains two plain-text files on the save volume: # /game-saves/panel-mods.txt — one @ModFolder per line → -mod= # /game-saves/panel-servermods.txt — one @ModFolder per line → -servermod= # Blank lines and lines starting with '#' are ignored. This lets the mod # manager edit a human-readable file and have the server pick up the new # load order on the next start without entrypoint code changes. build_mod_arg() { local file="$1" prefix="$2" [[ -s "$file" ]] || { echo ""; return; } local joined="" while IFS= read -r line || [[ -n "$line" ]]; do line="${line%$'\r'}" # strip trailing CR (Windows edits) line="${line#"${line%%[![:space:]]*}"}" # ltrim line="${line%"${line##*[![:space:]]}"}" # rtrim [[ -z "$line" || "$line" == \#* ]] && continue if [[ -z "$joined" ]]; then joined="$line" else joined="${joined};${line}" fi done < "$file" if [[ -n "$joined" ]]; then echo "${prefix}${joined}" fi } MOD_ARG="$(build_mod_arg "${SAVE_DIR}/panel-mods.txt" '-mod=')" SERVERMOD_ARG="$(build_mod_arg "${SAVE_DIR}/panel-servermods.txt" '-servermod=')" [[ -n "${MOD_ARG}" ]] && log "loading mods: ${MOD_ARG}" [[ -n "${SERVERMOD_ARG}" ]] && log "loading server-mods: ${SERVERMOD_ARG}" # DayZ's documented launch command: # ./DayZServer -config=serverDZ.cfg -port=2302 -BEpath=battleye \ # -profiles=profiles -dologs -adminlog -netlog \ # -freezecheck -doScriptLogs -cpuCount=2 # [-mod=@A;@B] [-servermod=@X] DZ_ARGS=( -config=serverDZ.cfg -port="${SERVER_PORT}" "-BEpath=${GAME_DIR}/battleye" -profiles=profiles -dologs -adminlog -netlog -freezecheck -doScriptLogs "-cpuCount=${CPU_COUNT}" ) [[ -n "${MOD_ARG}" ]] && DZ_ARGS+=("${MOD_ARG}") [[ -n "${SERVERMOD_ARG}" ]] && DZ_ARGS+=("${SERVERMOD_ARG}") exec stdbuf -oL -eL "${DEDI_EXE}" "${DZ_ARGS[@]}" & DZ_PID=$! wait "${DZ_PID}"