diff --git a/Dockerfile b/Dockerfile index 9937ae5..1eb6456 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,30 +1,31 @@ FROM debian:bullseye -# Replace shell with bash so we can source files -RUN rm /bin/sh && ln -s /bin/bash /bin/sh - -# Set debconf to run non-interactively -RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections +# Set debconf to run non-interactively and agree to the SteamCMD EULA +RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections \ + && echo steam steam/question select "I AGREE" | debconf-set-selections \ + && echo steam steam/license note '' | debconf-set-selections \ + && dpkg --add-architecture i386 # Add contrib and backports -RUN sed -i /etc/apt/sources.list -e 's/main/main contrib/' +RUN sed -i /etc/apt/sources.list -e 's/main/main contrib non-free/' -#RUN echo 'deb http://deb.debian.org/debian bullseye-backports main' >> /etc/apt/sources.list +RUN echo 'deb http://deb.debian.org/debian bullseye-backports main non-free' >> /etc/apt/sources.list -# Add 32 bit arch for steam crap -RUN dpkg --add-architecture i386 - -# Install necessary packages -RUN apt-get update && apt-get -y upgrade && apt-get -y install \ +# Install _only_ the necessary packages +RUN apt-get update && apt-get -y upgrade && apt-get -y install --no-install-recommends \ nano \ curl \ - lib32gcc-s1 \ - lib32stdc++6 \ + ca-certificates \ + lib32gcc-s1 \ + lib32stdc++6 \ + libcurl4:i386 \ + libsdl2-2.0-0:i386 \ libcap2 \ locales \ - psmisc \ + procps \ wget \ - rename + rename \ + steamcmd # Set the locale RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \ @@ -33,23 +34,17 @@ ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 -# Add steamcmd to the image. -RUN mkdir -p /steamcmd && \ - cd /steamcmd && \ - curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxf - +# steamcmd ends up in /usr/games +ENV PATH /usr/games:${PATH} -# Make our docker scripts easier to run -ENV PATH /files:/steamcmd:${PATH} +# Add the dayzserver to a directory in PATH. Might as well be /usr/games! +ADD files/dayzserver /usr/games # Setup a non-privileged user RUN groupadd user && \ - useradd -l -m -g user user - -# The volume needs to be owned by the user -RUN cd /home/user; rm -rf *; rm -rf .*; chown user:user /home/user -R - -# SteamCMD wants to manage itself, so it has to be owned by the docker user. -RUN chown user:user /steamcmd -R + useradd -l -g user user && \ + mkdir /home/user && \ + chown user:user /home/user # Use our non-privileged user USER user diff --git a/README.md b/README.md index fae9db7..61ea7d8 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # DayZDockerServer -A Linux DayZ server in a Docker container. -The main script's functionality is derived from [this project](https://github.com/thelastnoc/dayz-sa_linuxserver). -That functionality is described [here](https://steamcommunity.com/sharedfiles/filedetails/?id=1517338673). The goal is -to reproduce some of that functionality but also add more features. +A Linux [DayZ](https://dayz.com) server in a [Docker](https://docs.docker.com/) container. The main script's +functionality is derived from [this project](https://github.com/thelastnoc/dayz-sa_linuxserver). That functionality is +described [here](https://steamcommunity.com/sharedfiles/filedetails/?id=1517338673). The goal is to reproduce some of +that functionality but also add more features. ## Caveat Emptor @@ -16,6 +16,9 @@ This volume can get quite large. It will require at least 2G of disk space for t ## Configure and Build +Ensure [Docker](https://docs.docker.com/engine/install/) and [Docker compose](https://docs.docker.com/compose/install/) +are installed. + Edit `files/serverDZ.cfg` and set the values of any variables there. See the [documentation](https://forums.dayz.com/topic/239635-dayz-server-files-documentation/): @@ -65,6 +68,11 @@ docker-compose logs -f main ## Manage +This just runs a bash shell in the container. It allows for the file system and files to be easily inspected. +### Shell in the container +``` +docker-compose run --rm main bash +``` ### RCON Show the current Battle Eye configuration file (Derived from `files/beserver_x64.cfg`): ``` diff --git a/docker-compose.yml b/docker-compose.yml index 256aa9b..630d67f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,6 +13,3 @@ services: volumes: - homedir:/home/user - ./files:/files -# environment: -# # So we don't have to always download the full server when testing -# - FAKE_DAYZ_INSTALL=1 \ No newline at end of file diff --git a/files/beserver_x64.cfg b/files/beserver_x64.cfg deleted file mode 100644 index 459cb02..0000000 --- a/files/beserver_x64.cfg +++ /dev/null @@ -1,3 +0,0 @@ -RConPassword RCON_PASSWORD -RestrictRCon 1 -RConPort 2302 diff --git a/files/dayzserver b/files/dayzserver index 02eee39..6bc6557 100755 --- a/files/dayzserver +++ b/files/dayzserver @@ -4,14 +4,31 @@ # FIXME Set this in Docker somewhere ulimit -c 0 +# DayZ SteamID +appid=1042420 +dayz_id=221100 + +config=serverDZ.cfg +port=2302 +profile="-profiles=${HOME}/serverprofile/" + +# To log or not to log +#logs="-dologs -adminlog -netlog" +logs="-nologs" + +# mods="@CF;@community-Online-Tools;@Banov;@SimpleAutorun" +mods="" + +# modify carefully! server won't start if syntax is corrupt! +dayzparameter=" -config=${config} -port=${port} -mod='${mods}' -freezecheck ${profile} ${logs}" + # Colors default="\e[0m" red="\e[31m" green="\e[32m" -yellow="\e[33m" -lightyellow="\e[93m" -blue="\e[34m" +yellow="\e[93m" lightblue="\e[94m" +blue="\e[34m" magenta="\e[35m" cyan="\e[36m" @@ -20,15 +37,6 @@ CFG_SRC_FILES="/files" SERVER_FILES="${HOME}/serverfiles" SERVER_PROFILE="${HOME}/serverprofile" -# Default config file -DEFAULT_CFG="${CFG_SRC_FILES}/default.cfg" - -# Battle Eye files -BE_SERVER_FILE="beserver_x64.cfg" -BE_SERVER_DIR="${SERVER_FILES}/battleye" -BE_SERVER_DST="${BE_SERVER_DIR}/${BE_SERVER_FILE}" -BE_SERVER_SRC="${CFG_SRC_FILES}/${BE_SERVER_FILE}" - # Server configuration file SERVER_CFG_FILE="serverDZ.cfg" SERVER_CFG_DST="${SERVER_FILES}/${SERVER_CFG_FILE}" @@ -38,12 +46,41 @@ SERVER_CFG_SRC="${CFG_SRC_FILES}/${SERVER_CFG_FILE}" SERVER_INSTALL_FILE="${SERVER_FILES}/DayZServer" # Steam files -STEAM_LOGIN_DST="${HOME}/steamlogin" -STEAMCMD=steamcmd.sh +STEAM_LOGIN="${HOME}/steamlogin" +STEAMCMD=steamcmd # Workshop WORKSHOP_CFG="${HOME}/workshop.cfg" +# Other stuff +YES="${green}yes${default}" +NO="${red}no${default}" + +fn_usage(){ + echo -e " +${red}Bad option or arguments! ${yellow}${*}${default} + +Usage: ${green}$(basename $0)${yellow} option [ arg1 [ arg2 ] ] + +Options and arguments: + + install - Install the DayZ server files + login - Login to Steam + rcon - RCON Features + say - Send a message to players on the server + status - Shows the server's status as well as the state of the server files and mods (Needs install, update, etc.) + stop - Stop the server + update - Update the DayZ server files + workshop - Workshop Features + activate id [id...] - Activate one or many installed DayZ Workshop item by id + add id [id...] - Add one or many DayZ Workshop items by id + deactivate id [id...] - Deactivate one or many installed DayZ Workshop items by id - Keeps the addon files but excludes from -mod= + list - List Workshop items and their states (Active vs. Non) + remove id [id...] - Remove one or many Workshop items by id +${default}" + exit 1 +} + fn_prompt_yn(){ echo -n "${1} (y|N) " >&2 read -s -n 1 a @@ -59,7 +96,6 @@ fn_prompt_yn(){ } fn_loadconfig_dayz(){ - source ${DEFAULT_CFG} # Handle the server configuration file if [ ! -f ${SERVER_CFG_DST} ] then @@ -80,42 +116,15 @@ fn_loadconfig_dayz(){ fi } -# Checks for the destination file are already done before calls to this -fn_do_rcon(){ - if [ ! -d "${BE_SERVER_DIR}" ] - then - echo - echo -e "${yellow}DayZ is not installed yet. Can't manage RCON until then${default}" - echo - else - echo -n "Creating the Battle Eye configuration file " - cp "${BE_SERVER_SRC}" "${BE_SERVER_DST}" - # Set a random RCON password, unless one's set in the environment - if grep -q RCON_PASSWORD "${BE_SERVER_SRC}" - then - RCON_PASSWORD=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c10) - echo -e "using random RCON password ${yellow}${RCON_PASSWORD}${default}" - sed -i "${BE_SERVER_DST}" -e "s/RCON_PASSWORD/${RCON_PASSWORD}/" - else - echo "using the RCON_PASSWORD already set in ${BE_SERVER_SRC}." - fi - fi -} - -fn_create_beconfig(){ - if [ ! -f "${BE_SERVER_DST}" ] - then - echo -n "Creating Battle Eye RCON file " - fn_do_rcon - elif diff -q "${BE_SERVER_SRC}" "${BE_SERVER_DST}" > /dev/null - then - echo -n "Updating Battle Eye RCON file " - fn_do_rcon - fi -} - fn_start_dayz(){ - fn_create_beconfig + # Check for interactive shell + if [ -t 0 ] + then + echo + echo -e "Not starting the server in an interactive shell. Start the server using '${green}docker-compose up -d${default}'" + echo + exit + fi fn_loadconfig_dayz fn_workshop_mods printf "[ ${green}DayZ${default} ] Starting server...\n" @@ -140,18 +149,17 @@ fn_stop_dayz(){ } fn_steam_login(){ - if [ -f "${STEAM_LOGIN_DST}" ] + if [ -f "${STEAM_LOGIN}" ] then if fn_prompt_yn "The steam login is already set. Reset it?" then - rm -f "${STEAM_LOGIN_DST}" + rm -f "${STEAM_LOGIN}" else - echo - echo "Not reset. Nothing to do. Exiting..." + echo "Not reset." exit 0 fi fi - if [ ! -f "${STEAM_LOGIN_DST}" ] + if [ ! -f "${STEAM_LOGIN}" ] then echo "Setting up Steam credentials" echo -n "Steam Username (anonymous): " @@ -161,15 +169,15 @@ fn_steam_login(){ echo "Steam login set to 'anonymous'" steamlogin="anonymous" fi - echo "steamlogin=${steamlogin}" > "${STEAM_LOGIN_DST}" + echo "steamlogin=${steamlogin}" > "${STEAM_LOGIN}" ${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +quit fi } fn_steamlogin_dayz(){ - if [ -f "${STEAM_LOGIN_DST}" ] + if [ -f "${STEAM_LOGIN}" ] then - source "${STEAM_LOGIN_DST}" + source "${STEAM_LOGIN}" else echo "No cached Steam credentials. Please configure this now: " fn_steam_login @@ -209,27 +217,26 @@ fn_update_dayz(){ fn_steamlogin_dayz fn_loadconfig_dayz appmanifestfile=${SERVER_FILES}/steamapps/appmanifest_"${appid}".acf - printf "[ ... ] Checking for update: SteamCMD" + printf "[ ... ] Checking for update:" # gets currentbuild currentbuild=$(grep buildid "${appmanifestfile}" | tr '[:blank:]"' ' ' | tr -s ' ' | cut -d \ -f3) # Removes appinfo.vdf as a fix for not always getting up to date version info from SteamCMD if [ -f "${HOME}/Steam/appcache/appinfo.vdf" ]; then rm -f "${HOME}/Steam/appcache/appinfo.vdf" - sleep 1 fi # check for new build availablebuild=$(${STEAMCMD} +login "${steamlogin}" +app_info_update 1 +app_info_print "${appid}" +app_info_print \ "${appid}" +quit | sed -n '/branch/,$p' | grep -m 1 buildid | tr -cd '[:digit:]') if [ -z "${availablebuild}" ]; then - printf "\r[ ${red}FAIL${default} ] Checking for update: SteamCMD\n" - printf "\r[ ${red}FAIL${default} ] Checking for update: SteamCMD: Not returning version info\n" + printf "\r[ ${red}FAIL${default} ] Checking for update:\n" + printf "\r[ ${red}FAIL${default} ] Checking for update:: Not returning version info\n" exit else - printf "\r[ ${green}OK${default} ] Checking for update: SteamCMD" + printf "\r[ ${green}OK${default} ] Checking for update:" fi # compare builds if [ "${currentbuild}" != "${availablebuild}" ]; then - printf "\r[ ${green}OK${default} ] Checking for update: SteamCMD: Update available\n" + printf "\r[ ${green}OK${default} ] Checking for update:: Update available\n" printf "Update available:\n" printf "\tCurrent build: ${red}${currentbuild}${default}\n" printf "\tAvailable build: ${green}${availablebuild}${default}\n" @@ -239,7 +246,7 @@ fn_update_dayz(){ fn_runupdate_dayz fn_workshop_mods else - printf "\r[ ${green}OK${default} ] Checking for update: SteamCMD: No update available\n" + printf "\r[ ${green}OK${default} ] Checking for update:: No update available\n" printf "\nNo update available:\n" printf "\tCurrent version: ${green}${currentbuild}${default}\n" printf "\tAvailable version: ${green}${availablebuild}${default}\n" @@ -289,40 +296,48 @@ fn_workshop_mods(){ fn_rcon(){ case "${1}" in - show) - if [ ! -f "${BE_SERVER_DST}" ] - then - fn_do_rcon - fi - if [ -f "${BE_SERVER_DST}" ] - then - echo "==================================================================" - cat "${BE_SERVER_DST}" - echo "==================================================================" - fi + say) + echo "Sending message to server: '${1}'" ;; - reset) - if fn_prompt_yn "Reset RCON password?" - then - rm -f "${BE_SERVER_DST}" - fn_do_rcon - else - echo - echo "Not reset. Nothing to do. Exiting..." - exit 0 - fi + **) + fn_usage rcon "${1}" ;; esac } -fn_backup(){ - echo "Creating backup...WIP" +fn_status(){ + INSTALLED="${NO}" + LOGGED_IN="${NO}" + RUNNING="${NO}" + MOD_INSTALLED="${yellow}0${default}" + MOD_LIST="" + # DayZ Server files installation + if [ -f "${SERVER_INSTALL_FILE}" ] + then + INSTALLED="${YES}" + fi + # Logged into Steam + if [ -f "${STEAM_LOGIN}" ] + then + LOGGED_IN="${YES}" + fi + # Running or not + if pidof DayZServer + then + RUNNING="${YES}" + fi + # Number of mods plus the list denoting on or off + echo -e " +Status: + + Logged in to Steam: ${LOGGED_IN} + Server files installed: ${INSTALLED} + Mods installed: ${MOD_INSTALLED}${MOD_LIST} + Server running: ${RUNNING} +" } case "${1}" in - backup) - fn_backup - ;; install) fn_install_dayz ;; @@ -332,6 +347,12 @@ case "${1}" in rcon) fn_rcon "${2}" ;; + start) + fn_start_dayz + ;; + status) + fn_status + ;; stop) fn_stop_dayz ;; @@ -342,9 +363,6 @@ case "${1}" in fn_workshop_mods "${2}" ;; **) - echo - echo -e "${red}Unknown or missing option: '${1}'${default}" - echo -e "${green}Usage: $(basename $0) [ backup | install | login | rcon [ show | reset ] | stop | update | workshop [ add id | list | remove id ] ]${default}" - echo - ;; + fn_usage "$*" + ;; esac diff --git a/files/default.cfg b/files/default.cfg deleted file mode 100644 index d03605f..0000000 --- a/files/default.cfg +++ /dev/null @@ -1,30 +0,0 @@ -###################################### -# dayzserver config file # -# the parameter have to be within "" # -# otherwise the server wont start! # -############################################################################ -# https://forums.dayz.com/topic/239635-dayz-server-files-documentation/ -# launch parameters documentation -############################################################################# - -# DayZ SteamID -appid=1042420 -dayz_id=221100 -#stable=223350 -#exp_branch=1042420 - -# IMPORTANT PARAMETERS - DO NOT REMOVE! -config=serverDZ.cfg -port=2302 - -# DayZ Mods from Steam Workshop -# to enable mods, remove the # below and list the Mods like this: "-mod=@Mod1;@Mod2;@Mod3" -#workshop="-mod=" - -# optional - just remove the # to enable -BEpath="-BEpath=${HOME}/serverfiles/battleye/" -profiles="-profiles=${HOME}/serverprofile/" -#logs="-dologs -adminlog -netlog" - -# modify carefully! server won't start if syntax is corrupt! -dayzparameter=" -config=${config} -port=${port} -freezecheck ${BEpath} ${profiles} ${logs}" diff --git a/files/serverDZ.cfg b/files/serverDZ.cfg index 12b3acf..f842cb4 100644 --- a/files/serverDZ.cfg +++ b/files/serverDZ.cfg @@ -36,19 +36,17 @@ motdInterval = 1; // Time interval (in seconds) between each message maxPing= 200; // Max ping value until server kick the user (value in milliseconds) timeStampFormat = "Short"; // Format for timestamps in the .rpt file (value Full/Short) -logAverageFps = 1; // Logs the average server FPS (value in seconds), needs to have -dologs launch parameter active -logMemory = 1; // Logs the server memory usage (value in seconds), needs to have the -dologs launch parameter active -logPlayers = 1; // Logs the count of currently connected players (value in seconds), needs to have the -dologs launch parameter active +logAverageFps = 30; // Logs the average server FPS (value in seconds), needs to have -dologs launch parameter active +logMemory = 30; // Logs the server memory usage (value in seconds), needs to have the -dologs launch parameter active +logPlayers = 30; // Logs the count of currently connected players (value in seconds), needs to have the -dologs launch parameter active logFile = "server_console.log";// Saves the server console log to a file in the folder with the other server logs - adminLogPlayerHitsOnly = 0; // 1 - log player hits only / 0 - log all hits ( animals/infected ) adminLogPlacement = 0; // 1 - log placement action ( traps, tents ) adminLogBuildActions = 0; // 1 - log basebuilding actions ( build, dismantle, destroy ) adminLogPlayerList = 0; // 1 - log periodic player list with position every 5 minutes -enableDebugMonitor = 1; // shows info about the character using a debug window in a corner of the screen (value 0-1) - +enableDebugMonitor = 0; // shows info about the character using a debug window in a corner of the screen (value 0-1) steamQueryPort = 2305; // defines Steam query port, should fix the issue with server not being visible in client server browser