diff --git a/Dockerfile b/Dockerfile index aea44a7..5c8ba38 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,6 +33,13 @@ 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 && \ + curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxf - -C steamcmd + +# Make our docker scripts easier to run +ENV PATH /files:/steamcmd:${PATH} + # Setup a non-privileged user RUN groupadd user && \ useradd -l -m -g user user @@ -47,4 +54,4 @@ USER user WORKDIR /home/user # Run the server. -CMD ["/files/dayzserver", "start"] +CMD ["dayzserver", "start"] diff --git a/README.md b/README.md index 1813ee3..6cedff8 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,33 @@ # DayZDockerServer -A Linux DayZ server in a Docker container. Uses a modified version of https://github.com/thelastnoc/dayz-sa_linuxserver -for all the Steam management. More info here https://steamcommunity.com/sharedfiles/filedetails/?id=1517338673. -### Caveat Emptor -Uses a docker volume for the unprivileged user's home directory, which stores the DayZ server files plus SteamCMD, a -utility used to manage Steam content from the command line. This volume can get quite large. Out of the box, as of this -writing, DayZ Experimental is at 1.17 and the volume comes to about 1.8G of disk space once all the files are downloaded. +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 all that functionality and add even more while keeping it all in Docker. -### Setup, Build. and Configure +## Caveat Emptor -Edit `files/serverDZ.cfg` and set the server name (You don't really have to, but you should): +As of DayZ release 1.15, a [Linux DayZ server](https://steamdb.info/app/1042420/) was made available in Dayz +Experimental. This has not been officially released, so this will only run a DayZ Experimental server at the +moment. Only the [DayZ Experimental client](https://dayz.fandom.com/wiki/Experimental) will be able to connect to it. + +This process will create a docker volume for the unprivileged user's home directory, which stores the DayZ server files. +This volume can get quite large. It will require at least 2G of disk space for the default install. Much more with mods. + +## Setup, Build. and Configure + +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/): ``` hostname = "Something other than Server Name"; // Server name ``` -Optionally edit `files/beserver_x64.cfg` and set the rcon password: +Optionally edit `files/beserver_x64.cfg` and set the RCON password: ``` RConPassword h4CKm3 ``` -If the above step is not performed, a random rcon password will be generated and output on the first run. It can also be -obtained later and reset. +If the above step is not performed, a random RCON password will be generated and output on the first run. It can also be +obtained and reset. (See [Management](#manage)) Add your Steam credentials. This step is necessary if you want to add mods. The vanilla server is installable by setting the steamlogin to `anonymous`. Edit `files/steamlogin` and set the steam username. @@ -35,23 +43,32 @@ docker-compose build ``` Now login: ``` -docker-compose run --rm config +docker-compose run --rm run manage login ``` -### Run +## Run Launch the container into the background: ``` -docker-compose up -d dayzserver +docker-compose up -d run ``` Tail the log: ``` -docker-compose logs -f dayzserver +docker-compose logs -f run +``` + +## Manage + +### Workshop +To add a workshop item, edit `files/workshop.cfg` and add the item's id after the comment. Each id should be on its own +line, after the comment, which should not be removed. Install them: +``` +docker-compose run --rm manage ``` -### Workshop (TODO) -* Update/Add/Remove workshop files * Makage -mod= command line -### Maintenance (TODO) + +## TODO + * Update the server * Restart the server -* Rcon to the server? +* RCON to the server? * List current rocn password -* Detect changes to config files and propagate them \ No newline at end of file +* Detect changes to config files and propagate them, with prompting. diff --git a/docker-compose.yml b/docker-compose.yml index e34d75e..4dfb17e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,14 +5,7 @@ volumes: services: - config: - build: . - command: /files/login.sh - volumes: - - homedir:/home/user - - ./files:/files - - dayzserver: + run: build: . ports: - "2302:2302/udp" diff --git a/files/dayzserver b/files/dayzserver index 3fb6c33..16bb803 100755 --- a/files/dayzserver +++ b/files/dayzserver @@ -3,81 +3,81 @@ appid=1042420 dayz_id=221100 -if [ "${ansi}" != "off" ]; then - # echo colors - default="\e[0m" - red="\e[31m" - green="\e[32m" - yellow="\e[33m" - lightyellow="\e[93m" - blue="\e[34m" - lightblue="\e[94m" - magenta="\e[35m" - cyan="\e[36m" - # carriage return & erase to end of line - creeol="\r\033[K" -fi +default="\e[0m" +red="\e[31m" +green="\e[32m" +yellow="\e[33m" +lightyellow="\e[93m" +blue="\e[34m" +lightblue="\e[94m" +magenta="\e[35m" +cyan="\e[36m" + +STEAMCMD=/steamcmd/steamcmd.sh fn_loadconfig_dayz(){ source /files/default.cfg # Handle adding the server cfg file if [ ! -f ${HOME}/serverfiles/serverDZ.cfg ] then + echo "Creating initial serverDZ.cfg" + cp /files/serverDZ.cfg "${HOME}/serverfiles/serverDZ.cfg" + elif diff -q /files/default.cfg "${HOME}/serverfiles/serverDZ.cfg" > /dev/null + then + echo "Updating serverDZ.cfg" cp /files/serverDZ.cfg "${HOME}/serverfiles/serverDZ.cfg" fi } fn_create_beconfig(){ - # Set a random RCON password, unless one's set in the environment if [ -d "${HOME}/serverfiles/battleye" ] && [ ! -f "${HOME}/serverfiles/battleye/beserver_x64.cfg" ] then echo -n "Creating Battle Eye RCON file " - cp /files/beserver_x64.cfg "${HOME}/serverfiles/battleye/beserver_x64.cfg" - if grep RCON_PASSWORD /files/beserver_x64.cfg - then - RCON_PASSWORD=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c10) - echo -e "using random RCON password ${yellow}${RCON_PASSWORD}" - sed -i "${HOME}/serverfiles/battleye/beserver_x64.cfg" -e "s/RCON_PASSWORD/${RCON_PASSWORD}/" - else - echo "using the RCON_PASSWORD already set in files/beserver_x64.cfg." - fi + fn_do_rcon + elif diff -q /files/beserver_x64.cfg "${HOME}/serverfiles/battleye/beserver_x64.cfg" > /dev/null + then + echo -n "Updating Battle Eye RCON file " + fn_do_rcon + fi +} + +fn_do_rcon(){ + cp /files/beserver_x64.cfg "${HOME}/serverfiles/battleye/beserver_x64.cfg" + # Set a random RCON password, unless one's set in the environment + if grep -v RCON_PASSWORD /files/beserver_x64.cfg + then + RCON_PASSWORD=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c10) + echo -e "using random RCON password ${yellow}${RCON_PASSWORD}" + sed -i "${HOME}/serverfiles/battleye/beserver_x64.cfg" -e "s/RCON_PASSWORD/${RCON_PASSWORD}/" + else + echo "using the RCON_PASSWORD already set in files/beserver_x64.cfg." fi } fn_start_dayz(){ fn_loadconfig_dayz fn_workshop_mods - printf "[ ${green}DayZ${default} ] Starting server...\n" - cd ${HOME}/serverfiles - ./DayZServer $dayzparameter "$workshop" || ( - echo - echo -e "${yellow}========================================== error.log ==========================================" - find /home/user -name error.log -exec cat {} \; -exec rm -f {} \; - echo - echo -e "${yellow}========================================== script*.log ========================================" - find /home/user -name "script*.log" -exec cat {} \; -exec rm -f {} \; - echo - echo -e "${yellow}========================================== *.RPT ==============================================" - find /home/user -name "*.RPT" -exec cat {} \; -exec rm -f {} \; - echo - echo -e "${yellow}========================================== End crash log ======================================" - ) + printf "[ ${green}DayZ${default} ] Starting server...\n" + cd ${HOME}/serverfiles + ./DayZServer $dayzparameter "$workshop" || ( + echo + echo -e "${yellow}========================================== error.log ==========================================" + find /home/user -name error.log -exec cat {} \; -exec rm -f {} \; + echo + echo -e "${yellow}========================================== script*.log ========================================" + find /home/user -name "script*.log" -exec cat {} \; -exec rm -f {} \; + echo + echo -e "${yellow}========================================== *.RPT ==============================================" + find /home/user -name "*.RPT" -exec cat {} \; -exec rm -f {} \; + echo + echo -e "${yellow}========================================== End crash log ======================================" + ) } fn_steamlogin_dayz(){ source /files/steamlogin } -fn_install_steamcmd(){ - if [ ! -f "${HOME}/steamcmd/steamcmd.sh" ]; then - mkdir ${HOME}/steamcmd &> /dev/null - curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxf - -C steamcmd - printf "[ ${yellow}STEAM${default} ] Steamcmd installed\n" - else - printf "[ ${lightblue}STEAM${default} ] Steamcmd already installed\n" - fi -} - fn_install_dayz(){ if [ ! -f "${HOME}/serverfiles/DayZServer" ]; then mkdir ${HOME}/serverfiles &> /dev/null @@ -92,7 +92,7 @@ fn_install_dayz(){ fn_runupdate_dayz(){ fn_loadconfig_dayz - ${HOME}/steamcmd/steamcmd.sh +force_install_dir ${HOME}/serverfiles +login "${steamlogin}" +app_update "${appid}" +quit + ${STEAMCMD} +force_install_dir ${HOME}/serverfiles +login "${steamlogin}" +app_update "${appid}" +quit } fn_update_dayz(){ @@ -108,7 +108,7 @@ fn_update_dayz(){ sleep 1 fi # check for new build - availablebuild=$(${HOME}/steamcmd/steamcmd.sh +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:]') + 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" @@ -138,7 +138,7 @@ fn_update_dayz(){ fn_runvalidate_dayz(){ fn_loadconfig_dayz - ${HOME}/steamcmd/steamcmd.sh +force_install_dir ${HOME}/serverfiles +login "${steamlogin}" +app_update "${appid}" validate +quit + ${STEAMCMD} +force_install_dir ${HOME}/serverfiles +login "${steamlogin}" +app_update "${appid}" validate +quit } fn_workshop_mods(){ @@ -163,7 +163,7 @@ fn_workshop_mods(){ fi done # download mods - ${HOME}/steamcmd/steamcmd.sh +force_install_dir ${HOME}/serverfiles +login "${steamlogin}" ${workshoplist} +quit + ${STEAMCMD} +force_install_dir ${HOME}/serverfiles +login "${steamlogin}" ${workshoplist} +quit # link mods for i in "${workshopID[@]}" do diff --git a/files/login.sh b/files/login.sh deleted file mode 100755 index 6144c22..0000000 --- a/files/login.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -if [ -f ${HOME}/.steamlogin ] -then - echo "The file .steamlogin already exists. Remove it first then run this again. (See README.md)" - exit 1 -else - source /files/dayzserver - fn_install_steamcmd - echo "Setting up Steam credentials" - cp /files/steamlogin "${HOME}/.steamlogin" - source "${HOME}/.steamlogin" - ${HOME}/steamcmd/steamcmd.sh +force_install_dir ${HOME}/serverfiles +login "${steamlogin}" +quit -fi diff --git a/files/manage b/files/manage new file mode 100755 index 0000000..7bc9989 --- /dev/null +++ b/files/manage @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +if [[ "${1}" = "login" ]] +then + if [ -f ${HOME}/.steamlogin ] + then + echo -n "The steam login is already set. Reset it? (Y|n): " + read -s -n 1 a + a=$(echo ${a} | tr A-Z a-z) + if [[ "${a}" = "y" ]] + then + rm -f ${HOME}/.steamlogin + else + echo "Not reset. Nothing to do. Exiting..." + exit 0 + fi + fi + if [ ! -f ${HOME}/.steamlogin ] + then + echo "Setting up Steam credentials" + cp /files/steamlogin "${HOME}/.steamlogin" + source "${HOME}/.steamlogin" + steamcmd.sh +force_install_dir ${HOME}/serverfiles +login "${steamlogin}" +quit + fi +elif [[ "${1}" = "workshop" ]] +then + echo "Updating workshopp..." +elif [[ "${1}" = "backup" ]] +then + echo "Creating backup..." +elif [[ "${1}" = "rconpassword" ]] +then + echo "The RCON password is: ..." +else + echo "Unknown option '${1}'" + echo "Usage: manage backup | login | workshop | rconpassword" + exit 0 +fi +