├── .dockerignore ├── TTT ├── Dockerfile └── server.cfg.default ├── .project ├── test ├── testHealth.sh ├── testCaseQuick.sh ├── testStyle.sh └── testBuild.sh ├── hooks └── pre_push ├── lgsm ├── createAlias.sh ├── initCron.sh └── entrypoint.sh ├── docker-compose.yml ├── gmod ├── prepareServer.sh ├── forceWorkshopDownload.sh ├── initConfig.sh ├── installAndMountAddons.sh └── common.cfg ├── LICENSE ├── Dockerfile └── README.md /.dockerignore: -------------------------------------------------------------------------------- 1 | .project 2 | test/* 3 | LICENSE 4 | README.md 5 | -------------------------------------------------------------------------------- /TTT/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG SUFFIX="" 2 | 3 | FROM jusito/docker-ttt:gmod_debian${SUFFIX} 4 | 5 | ENV SERVER_GAMEMODE="terrortown" 6 | 7 | COPY "server.cfg.default" "/home/server.cfg.default" 8 | 9 | USER "$USER_ID:$GROUP_ID" 10 | 11 | VOLUME "$SERVER_PATH" -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | docker-ttt 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/testHealth.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "${DEBUGGING:?}" = "true" ]; then 4 | set -o xtrace 5 | fi 6 | 7 | set -o errexit 8 | set -o nounset 9 | set -o pipefail 10 | 11 | docker exec -it CONTAINER ./home/steam/gmodserver details 12 | 13 | Status: OFFLINE -> fail Health -------------------------------------------------------------------------------- /hooks/pre_push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -o errexit 4 | set -o nounset 5 | 6 | imageSuffix="" 7 | if [ "$SOURCE_BRANCH" != "master" ]; then 8 | imageSuffix="-$(echo "$SOURCE_BRANCH" | sed 's/\//-/g')" 9 | fi 10 | 11 | echo "current directory:" 12 | echo "$(pwd)" 13 | ls -lA . 14 | bash test/testBuild.sh "$imageSuffix" --skip-ttt --push 15 | -------------------------------------------------------------------------------- /lgsm/createAlias.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "${DEBUGGING}" = "true" ]; then 4 | set -o xtrace 5 | fi 6 | 7 | set -o errexit 8 | set -o nounset 9 | 10 | name=$1 11 | command=$2 12 | file="/usr/local/bin/$name" 13 | 14 | echo "[createAlias.sh] $name = $command" 15 | 16 | if [ -f "$file" ]; then 17 | echo "[createAlias.sh]error file already exists => cant create alias with this method" 18 | else 19 | echo '#!/bin/bash' > "$file" 20 | echo "$command" >> "$file" && \ 21 | chmod a=rx "$file" 22 | fi 23 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | volumes: 2 | TTTDev: 3 | 4 | services: 5 | ttt: 6 | build: . 7 | ports: 8 | - 27015:27015/tcp 9 | - 27015:27015/udp 10 | environment: 11 | INSTALL_CSS: "true" 12 | SERVER_DEFAULT_MAP: ttt_lttp_kakariko_a4 13 | SERVER_PORT: 27015 14 | SERVER_NAME: "Example Name" 15 | SERVER_PASSWORD: securePassword 16 | SERVER_VOICE_ENABLE: 0 17 | SERVER_MAX_PLAYERS: 20 18 | SERVER_RCON_PASSWORD: securePassword 19 | WORKSHOP_COLLECTION_ID: 1895900191 20 | volumes: 21 | - TTTDev:/home/steam/serverfiles 22 | -------------------------------------------------------------------------------- /test/testCaseQuick.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "${DEBUGGING}" = "true" ]; then 4 | set -o xtrace 5 | else 6 | DEBUGGING="false" 7 | fi 8 | 9 | set -o errexit 10 | set -o nounset 11 | set -o pipefail 12 | 13 | #bash test/testStyle.sh 14 | 15 | bash test/testBuild.sh 16 | 17 | 18 | echo "[testRun][INFO]running" 19 | if ! docker run -ti --name "JusitoTesting" --rm -e TEST_MODE=true -e DEBUGGING="$DEBUGGING" -e SERVER_PASSWORD="testpw" -e SERVER_MAX_PLAYERS="10" "jusito/docker-ttt:gmod_ttt_debian"; then 20 | echo "[testRun][ERROR]run test failed for docker-ttt:gmod_ttt_debian" 21 | exit 1 22 | fi 23 | docker stop "JusitoTesting" || true 24 | docker rm "JusitoTesting" || true -------------------------------------------------------------------------------- /gmod/prepareServer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "${DEBUGGING}" = "true" ]; then 4 | set -o xtrace 5 | fi 6 | 7 | set -o errexit 8 | set -o nounset 9 | #./prepareServer.sh: 9: set: Illegal option -o pipefail 10 | #set -o pipefail 11 | 12 | # copy lgsm config 13 | mkdir -p "/home/steam/lgsm/config-lgsm/gmodserver/" 14 | cp -f "/home/common.cfg" "/home/steam/lgsm/config-lgsm/gmodserver/common.cfg" # common.cfg should be target, but is wrong, maybe a bug. (gmodserver working) 15 | 16 | cd "/home" 17 | echo "[prepareServer.sh]check configurations" 18 | ./initConfig.sh 19 | echo "[prepareServer.sh]force workshop download" 20 | ./forceWorkshopDownload.sh 21 | echo "[prepareServer.sh]install & mount gamefiles" 22 | ./installAndMountAddons.sh 23 | cd "$STEAM_PATH" 24 | -------------------------------------------------------------------------------- /lgsm/initCron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "${DEBUGGING}" = "true" ]; then 4 | set -o xtrace 5 | fi 6 | 7 | set -o errexit 8 | set -o pipefail 9 | set -o nounset 10 | 11 | LOG_PATH="$STEAM_PATH/logs" 12 | CRON="$LOG_PATH/lgsm.cron" 13 | CRON_LOG="$LOG_PATH/cron.log" 14 | 15 | #set up cronjob 16 | mkdir "$LOG_PATH" || true 17 | rm -f "$CRON" || true 18 | touch "$CRON" 19 | # false positive 20 | # shellcheck disable=SC2129 21 | echo "$CRON_MONITOR $STEAM_PATH/gmodserver monitor > '$LOG_PATH/monitor.log' 2>&1" >> "$CRON" 22 | # shellcheck disable=SC2129 23 | echo "$CRON_UPDATE $STEAM_PATH/gmodserver update > '$LOG_PATH/update.log' 2>&1" >> "$CRON" 24 | # shellcheck disable=SC2129 25 | echo "$CRON_FORCE_UPDATE $STEAM_PATH/gmodserver force-update >'$LOG_PATH/force-update.log' 2>&1" >> "$CRON" 26 | # shellcheck disable=SC2129 27 | echo "$CRON_LOG_ROTATE mv -f '$CRON_LOG' '${CRON_LOG}.old'" >> "$CRON" 28 | echo "" >> "$CRON" 29 | 30 | if [ -e "$CRON_LOG" ]; then 31 | mv -f "$CRON_LOG" "${CRON_LOG}.old" 32 | fi 33 | 34 | supercronic "$CRON" 2> "$LOG_PATH/cron.log" & -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 jusito 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /gmod/forceWorkshopDownload.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "${DEBUGGING}" = "true" ]; then 4 | set -o xtrace 5 | fi 6 | 7 | set -o errexit 8 | set -o nounset 9 | set -o pipefail 10 | 11 | #using WORKSHOP_COLLECTION_ID 12 | LUA_PATH="${SERVER_PATH}/garrysmod/lua/autorun/server" 13 | LUA_FILE="${LUA_PATH}/workshop_autoload.lua" 14 | 15 | #remove old file 16 | if [ -e "$LUA_FILE" ]; then 17 | rm "$LUA_FILE" 18 | else 19 | mkdir -p "$LUA_PATH" 20 | fi 21 | 22 | if [ "$WORKSHOP_COLLECTION_ID" = "0" ] || [ "$WORKSHOP_COLLECTION_ID" = "" ] || [ "$WORKSHOP_AUTOLOAD" != "true" ]; then 23 | echo "[forceWorkshopDownload.sh]No auto workshop download" 24 | else 25 | echo "[forceWorkshopDownload.sh]processing workshop collection ${WORKSHOP_COLLECTION_ID}" 26 | touch "$LUA_FILE" 27 | arr=$(wget -q -O - https://steamcommunity.com/sharedfiles/filedetails/?id="${WORKSHOP_COLLECTION_ID}" | tr '\n' ' ' | grep -Po '"workshopItem"[^"]+"https://steamcommunity.com/sharedfiles/filedetails/\?id=(\d+)' | grep -Po '\d\d\d+' ) 28 | str="" 29 | # resplitting needed here, otherwise one string with complete ids 30 | # shellcheck disable=SC2068 31 | for i in ${arr[@]} 32 | do 33 | str=${str}"resource.AddWorkshop( \"${i}\" )"$'\n' 34 | done 35 | echo "$str" > "$LUA_FILE" 36 | fi 37 | 38 | -------------------------------------------------------------------------------- /test/testStyle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "${DEBUGGING}" = "true" ]; then 4 | set -o xtrace 5 | fi 6 | 7 | set -o errexit 8 | set -o nounset 9 | set -o pipefail 10 | 11 | # test sha3sums 12 | 13 | #if ! printf '%s %s' "$(grep -Eo "grep -Eq '\^[^\\]+" Dockerfile | sed 's/...........//')" "checkHealth.sh" | sha3sum -c ; then 14 | # echo "[testStyle][ERROR]Sha3sum of checkHealth.sh in Dockerfile invalid" 15 | # exit 2 16 | #fi 17 | 18 | directory="$PWD" 19 | echo "[testStyle][INFO]workdir $directory" 20 | 21 | check() { 22 | file="$1" 23 | exclude="" 24 | if [ -n "$2" ]; then 25 | exclude="--exclude=$2" 26 | fi 27 | 28 | echo "[testStyle][INFO]processing $file with extra arg: $exclude" 29 | # shellcheck disable=SC2086 30 | if shellcheck $exclude "$file"; then 31 | return 0 32 | else 33 | echo "[testStyle][ERROR]style is bad" 34 | return 1 35 | fi 36 | } 37 | 38 | 39 | find "${directory}" -maxdepth 1 -type f -iname '*.sh' | 40 | while read -r filename 41 | do 42 | if ! check "$filename" ''; then 43 | exit 1 44 | fi 45 | done 46 | 47 | # shellcheck disable=SC2181 48 | if [ "$?" = "0" ]; then 49 | echo "[testStyle][INFO]all elements passed style check" 50 | exit 0 51 | else 52 | echo "[testStyle][ERROR]style in at least one element looks bad" 53 | exit 1 54 | fi -------------------------------------------------------------------------------- /test/testBuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | readonly SUFFIX="$1" 4 | readonly BUILD_TTT="$(grep -qF -e '--skip-ttt' <<< "$@" && echo false || echo true)" 5 | readonly PUSH="$(grep -qF -e '--push' <<< "$@" && echo true || echo false)" 6 | readonly repository="${DOCKER_REPO:-jusito/docker-ttt}" 7 | 8 | if [ "${DEBUGGING}" = "true" ]; then 9 | set -o xtrace 10 | else 11 | DEBUGGING="false" 12 | fi 13 | 14 | set -o errexit 15 | set -o nounset 16 | set -o pipefail 17 | 18 | function process() { 19 | tag_prefix="$1" 20 | target="$2" 21 | cache_option="$(grep -qF -e '--no-cache' <<< "$@" && echo "--no-cache" || echo "")" 22 | 23 | docker rmi "$repository:$tag_prefix${SUFFIX}" || true 24 | docker build --target "$target" $cache_option -t "$repository:$tag_prefix${SUFFIX}" . 25 | if "$PUSH"; then 26 | docker push "$repository:$tag_prefix${SUFFIX}" 27 | fi 28 | } 29 | 30 | echo "[testBuild][INFO] build" 31 | 32 | process "lgsm_debian" "lgsm" --no-cache 33 | process "gmod_debian" "gmod" 34 | if "$BUILD_TTT"; then 35 | process "gmod_ttt_debian" "TTT" 36 | fi 37 | 38 | docker rmi "$repository:latest${SUFFIX}" || true 39 | docker tag "$repository:gmod_ttt_debian${SUFFIX}" "$repository:latest${SUFFIX}" 40 | if "$PUSH"; then 41 | docker push "$repository:latest${SUFFIX}" 42 | fi 43 | 44 | echo "[testBuild][INFO] build done!" 45 | -------------------------------------------------------------------------------- /gmod/initConfig.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "${DEBUGGING}" = "true" ]; then 4 | set -o xtrace 5 | fi 6 | 7 | set -o errexit 8 | set -o nounset 9 | set -o pipefail 10 | 11 | CFG_PATH="${SERVER_PATH}/garrysmod/cfg/gmodserver.cfg" 12 | 13 | function configReplace() { 14 | local source="$1" 15 | local target="$2" 16 | 17 | count=$(grep -Ece "^\s*${source}\s" "${CFG_PATH}") 18 | 19 | echo "[initConfig.sh]Request for replacing \"$source\" to \"$target\", source is found $count times" 20 | 21 | sed -E -i "/^\s${source}\s.*/d" "${CFG_PATH}" 22 | 23 | local file_ends_on_newline=$([ "$(tail -c1 "${CFG_PATH}" | wc -l)" -eq 1 ] && echo true || echo false) 24 | if ! $file_ends_on_newline; then 25 | echo "" >> "${CFG_PATH}" 26 | fi 27 | echo "$source \"$target\"" >> "${CFG_PATH}" 28 | } 29 | 30 | #create default server.config 31 | # not empty: grep -q '[^[:space:]]' < 'server.cfg' && echo "not empty" 32 | if [ ! -e "${CFG_PATH}" ] || [ "0" = "$(grep -oc '[^[:space:]]' "${CFG_PATH}")" ]; then 33 | mkdir -p "${SERVER_PATH}/garrysmod/cfg" || true 34 | cp -f "/home/server.cfg.default" "${CFG_PATH}" 35 | chown "$USER_ID:$GROUP_ID" "${CFG_PATH}" 36 | chmod u+rw "${CFG_PATH}" 37 | fi 38 | 39 | # set hostname & password, working if only one entry is in 40 | if [ -n "${SERVER_NAME}" ]; then 41 | configReplace "hostname" "$SERVER_NAME" 42 | fi 43 | if [ -n "${SERVER_PASSWORD}" ]; then 44 | configReplace "sv_password" "$SERVER_PASSWORD" 45 | fi 46 | if [ -n "${SERVER_RCON_PASSWORD}" ]; then 47 | configReplace "rcon_password" "$SERVER_RCON_PASSWORD" 48 | fi 49 | if [ -n "${SERVER_VOICE_ENABLE}" ]; then 50 | configReplace "sv_voiceenable" "$SERVER_VOICE_ENABLE" 51 | fi 52 | -------------------------------------------------------------------------------- /lgsm/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "${DEBUGGING}" = "true" ]; then 4 | set -o xtrace 5 | fi 6 | 7 | set -o errexit 8 | set -o nounset 9 | set -o pipefail 10 | 11 | echo "[entrypoint.sh]starting entrypoint.sh" 12 | set -e 13 | 14 | 15 | 16 | 17 | 18 | 19 | # --- Install / Update --- 20 | cd "$STEAM_PATH" 21 | if [ -n "$SERVER_EXECUTABLE" ] && [ -e "${STEAM_PATH}/$SERVER_EXECUTABLE" ] && [ -d "$STEAM_CMD" ]; then 22 | echo "[entrypoint.sh]updating..." 23 | if "$LGSM_UPDATE"; then 24 | ./"$SERVER_EXECUTABLE" update-lgsm || ( 25 | # this sometimes prevent updating, I dont get it why this is an issue 26 | rm -rf "${STEAM_PATH}/lgsm/functions/lgsm" 27 | ./"$SERVER_EXECUTABLE" update-lgsm 28 | ) 29 | fi 30 | ./"$SERVER_EXECUTABLE" update 31 | else 32 | echo "[entrypoint.sh]installing..." 33 | bash linuxgsm.sh "$SERVER_GAME" 34 | ./"$SERVER_EXECUTABLE" auto-install 35 | fi 36 | echo "[entrypoint.sh]update / installation done!" 37 | 38 | if [ -e "/home/prepareServer.sh" ]; then 39 | cd /home 40 | ./prepareServer.sh "$@" 41 | cd "$STEAM_PATH" 42 | fi 43 | 44 | 45 | 46 | 47 | 48 | 49 | # --- Start Server --- 50 | #start server 51 | IS_RUNNING="true" 52 | function stopServer() { 53 | echo "stopping server..." 54 | cd "${STEAM_PATH}" 55 | pid=$(pidof "$SERVER_EXECUTABLE") 56 | kill -2 "$pid" || true 57 | echo "server stopped!" 58 | echo "stopping entrypoint..." 59 | IS_RUNNING="false" 60 | echo "done!" 61 | } 62 | ./"$SERVER_EXECUTABLE" start 63 | trap stopServer SIGTERM 64 | 65 | #start cron 66 | bash "/home/initCron.sh" 67 | 68 | 69 | 70 | 71 | 72 | # --- Wait for Shutdown --- 73 | echo "Server is running, waiting for SIGTERM" 74 | tail -f /home/steam/log/console/gmodserver-console.log & 75 | while [ "$IS_RUNNING" = "true" ] 76 | do 77 | sleep 1s 78 | done 79 | echo "entrypoint stopped" 80 | exit 0 81 | -------------------------------------------------------------------------------- /TTT/server.cfg.default: -------------------------------------------------------------------------------- 1 | hostname "" 2 | sv_password "" 3 | sv_voiceenable 0 4 | 5 | sv_contact "unknown" 6 | 7 | 8 | // rcon passsword 9 | sv_rcon_banpenalty 5 10 | sv_rcon_maxfailures 3 11 | 12 | //DNA 13 | ttt_killer_dna_range 300 14 | ttt_killer_dna_basetime 100 15 | 16 | 17 | //Prep 18 | ttt_firstpreptime 60 19 | ttt_preptime_seconds 30 20 | ttt_posttime_seconds 3 21 | 22 | 23 | //Round length 24 | ttt_haste 0 25 | // ttt_haste_starting_minutes 5 26 | // ttt_haste_minutes_per_death 0.5 27 | 28 | ttt_roundtime_minutes 10 29 | 30 | 31 | 32 | //Map Switching 33 | ttt_round_limit 10 34 | ttt_time_limit_minutes 75 35 | 36 | //ttt_always_use_mapcycle 0 37 | 38 | 39 | //Player Counts 40 | ttt_minimum_players 2 41 | ttt_traitor_pct 0.4 42 | ttt_traitor_max 32 43 | ttt_detective_pct 0.1 44 | ttt_detective_max 32 45 | ttt_detective_min_players 6 46 | ttt_detective_karma_min 600 47 | 48 | 49 | //Karma 50 | ttt_karma 1 51 | ttt_karma_strict 1 52 | ttt_karma_starting 1000 53 | ttt_karma_max 1000 54 | ttt_karma_ratio 0.001 55 | ttt_karma_kill_penalty 50 56 | ttt_karma_round_increment 5 57 | ttt_karma_clean_bonus 30 58 | ttt_karma_traitordmg_ratio 0.0003 59 | ttt_karma_traitorkill_bonus 100 60 | ttt_karma_low_autokick 1 61 | ttt_karma_low_amount 300 62 | ttt_karma_low_ban 0 63 | ttt_karma_low_ban_minutes 60 64 | ttt_karma_persist 1 65 | ttt_karma_clean_half 0.25 66 | 67 | //Other 68 | ttt_postround_dm 0 69 | ttt_no_nade_throw_during_prep 0 70 | ttt_weapon_carrying 1 71 | ttt_weapon_carrying_range 50 72 | ttt_teleport_telefrags 1 73 | ttt_ragdoll_pinning 1 74 | ttt_ragdoll_pinning_innocents 1 75 | ttt_use_weapon_spawn_scripts 1 76 | ttt_spawn_wave_interval 2 77 | ttt_allow_discomb_jump 1 78 | ttt_debug_preventwin 0 79 | 80 | // server logging 81 | log on 82 | sv_logbans 1 83 | sv_logecho 1 84 | sv_logfile 0 85 | sv_log_onefile 0 86 | 87 | // operation 88 | sv_lan 0 89 | sv_region 3 //Europa 90 | 91 | // traitor 92 | ttt_credits_detectivekill 2 93 | ttt_credits_award_repeat 0.5 94 | 95 | // fastdl 96 | sv_allowdownload 1 97 | sv_allowupload 0 98 | // sv_downloadurl "your url" 99 | 100 | exec banned_user.cfg 101 | exec banned_ip.cfg -------------------------------------------------------------------------------- /gmod/installAndMountAddons.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "${DEBUGGING}" = "true" ]; then 4 | set -o xtrace 5 | fi 6 | 7 | set -o errexit 8 | set -o nounset 9 | set -o pipefail 10 | cd "$STEAM_CMD" 11 | mount='"mountcfg"'$'\n{\n' 12 | if [ "$INSTALL_CSS" = "true" ]; then 13 | echo "[installAndMountAddons.sh]installing & mounting css" 14 | ./steamcmd.sh +force_install_dir "$CSS_PATH" +login anonymous +app_update 232330 validate +quit 15 | mount=${mount}' "cstrike" "'"${CSS_PATH}/cstrike"$'"\n' 16 | if [ "$INSTALL_HL2" != "true" ]; then 17 | mount=${mount}' "hl2" "'"${CSS_PATH}/hl2"$'"\n' 18 | fi 19 | fi 20 | if [ "$INSTALL_HL2" = "true" ]; then 21 | echo "[installAndMountAddons.sh]installing & mounting hl2" 22 | ./steamcmd.sh +force_install_dir "$HL2_PATH" +login anonymous +app_update 232370 validate +quit 23 | mount=${mount}' "hl2" "'"${HL2_PATH}/hl2"$'"\n' 24 | mount=${mount}' "hl2mp" "'"${HL2_PATH}/hl2mp"$'"\n' 25 | fi 26 | if [ "$INSTALL_TF2" = "true" ]; then 27 | echo "[installAndMountAddons.sh]installing & mounting tf2" 28 | ./steamcmd.sh +force_install_dir "$TF2_PATH" +login anonymous +app_update 232250 validate +quit 29 | mount=${mount}' "tf2" "'"${TF2_PATH}/tf"$'"\n' 30 | if [ "$INSTALL_CSS" != "true" ] && [ "$INSTALL_HL2" != "true" ]; then 31 | mount=${mount}' "hl2" "'"${TF2_PATH}/hl2"$'"\n' 32 | fi 33 | fi 34 | if [ "$INSTALL_HLDM" = "true" ]; then 35 | echo "[installAndMountAddons.sh]installing & mounting hldm" 36 | ./steamcmd.sh +force_install_dir "$HLDM_PATH" +login anonymous +app_update 255470 validate +quit 37 | mount=${mount}' "hl1" "'"${HLDM_PATH}/hl1"$'"\n' 38 | mount=${mount}' "hldm" "'"${HLDM_PATH}/hldm"$'"\n' 39 | if [ "$INSTALL_CSS" != "true" ] && [ "$INSTALL_HL2" != "true" ] && [ "$INSTALL_TF2" != "true" ]; then 40 | mount=${mount}' "hl2" "'"${HLDM_PATH}/hl2"$'"\n' 41 | fi 42 | fi 43 | mount=${mount}$'}\n' 44 | 45 | 46 | if [ ! -e "${SERVER_PATH}/garrysmod/cfg" ]; then 47 | mkdir -p "${SERVER_PATH}/garrysmod/cfg" 48 | fi 49 | if [ -e "${SERVER_PATH}/garrysmod/cfg/mount.cfg" ]; then 50 | rm "${SERVER_PATH}/garrysmod/cfg/mount.cfg" 51 | fi 52 | touch "${SERVER_PATH}/garrysmod/cfg/mount.cfg" 53 | echo "$mount" > "${SERVER_PATH}/garrysmod/cfg/mount.cfg" 54 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:12-slim as lgsm 2 | 3 | # Const \\ Overwrite Env \\ Configs possible \\ Configs needed 4 | # C.UTF-8 -> en_US.UTF-8 5 | ENV STEAM_PATH="/home/steam" \ 6 | SERVER_PATH="/home/steam/serverfiles" \ 7 | STEAM_CMD="/home/steam/.steam/steamcmd" \ 8 | GROUP_ID=10000 \ 9 | USER_ID=10000 \ 10 | DOCKER_USER=steam \ 11 | SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.2.38/supercronic-linux-amd64 \ 12 | SUPERCRONIC=supercronic-linux-amd64 \ 13 | SUPERCRONIC_SHA1SUM=bc072eba2ae083849d5f86c6bd1f345f6ed902d0 \ 14 | \ 15 | \ 16 | LANG=C.UTF-8 \ 17 | TERM=xterm \ 18 | \ 19 | \ 20 | DEBUGGING=false \ 21 | CRON_MONITOR="*/5 * * * *" \ 22 | CRON_UPDATE="*/30 * * * *" \ 23 | CRON_FORCE_UPDATE="0 10 * * 0" \ 24 | CRON_LOG_ROTATE="0 0 * * 0" \ 25 | \ 26 | \ 27 | SERVER_EXECUTABLE="" \ 28 | SERVER_GAME="" \ 29 | TZ="Europe/Berlin" 30 | #https://en.wikipedia.org/wiki/List_of_tz_database_time_zones 31 | 32 | ENTRYPOINT ["./home/entrypoint.sh"] 33 | 34 | #WORKDIR "$STEAM_PATH" 35 | 36 | COPY ["lgsm/entrypoint.sh", "lgsm/initCron.sh", "lgsm/createAlias.sh", "/home/"] 37 | 38 | # procps needed for ps command 39 | # iproute2 needed because of "-slim" 40 | RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ 41 | --mount=type=cache,target=/var/lib/apt,sharing=locked \ 42 | set -eux; \ 43 | dpkg --add-architecture i386; \ 44 | apt-get update -y; \ 45 | DEBIAN_FRONTEND=noninteractive apt-get install -y bc binutils bsdmainutils bzip2 ca-certificates cpio curl distro-info file gzip hostname jq lib32gcc-s1 lib32stdc++6 netcat-openbsd pigz python3 tar tmux unzip util-linux uuid-runtime wget xz-utils \ 46 | libtinfo5:i386 \ 47 | libsdl2-2.0-0:i386 \ 48 | procps iproute2; \ 49 | \ 50 | groupadd -g $GROUP_ID $DOCKER_USER; \ 51 | useradd -d "$STEAM_PATH" -g $GROUP_ID -u $USER_ID -m $DOCKER_USER; \ 52 | chown "$DOCKER_USER:$DOCKER_USER" /home/entrypoint.sh; \ 53 | chown "$DOCKER_USER:$DOCKER_USER" /home/initCron.sh; \ 54 | mkdir -p "$SERVER_PATH"; \ 55 | chown -R "$DOCKER_USER:$DOCKER_USER" "$STEAM_PATH"; \ 56 | chmod a=rx /home/entrypoint.sh; \ 57 | chmod a=rx /home/initCron.sh; \ 58 | chmod a=rx /home/createAlias.sh; \ 59 | \ 60 | ulimit -n 2048; \ 61 | \ 62 | wget -O "$STEAM_PATH/linuxgsm.sh" "https://linuxgsm.sh"; \ 63 | chown "$DOCKER_USER:$DOCKER_USER" "$STEAM_PATH/linuxgsm.sh"; \ 64 | chmod +x "$STEAM_PATH/linuxgsm.sh"; \ 65 | \ 66 | \ 67 | wget -O "${SUPERCRONIC}" "$SUPERCRONIC_URL"; \ 68 | echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c -; \ 69 | chmod +x "$SUPERCRONIC"; \ 70 | mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}"; \ 71 | ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic 72 | 73 | FROM lgsm as gmod 74 | 75 | # Const \\ Overwrite Env \\ Configs optional 76 | ENV CSS_PATH="/home/steam/addons/css" \ 77 | HL2_PATH="/home/steam/addons/hl2" \ 78 | HLDM_PATH="/home/steam/addons/hldm" \ 79 | TF2_PATH="/home/steam/addons/tf2" \ 80 | \ 81 | \ 82 | SERVER_EXECUTABLE="gmodserver" \ 83 | SERVER_GAME="gmodserver" \ 84 | \ 85 | \ 86 | WORKSHOP_COLLECTION_ID="" \ 87 | WORKSHOP_API_KEY="" \ 88 | WORKSHOP_AUTOLOAD="true" \ 89 | SERVER_NAME="LinuxGSM" \ 90 | SERVER_PASSWORD="" \ 91 | SERVER_RCON_PASSWORD="" \ 92 | SERVER_VOICE_ENABLE="1" \ 93 | SERVER_IP="0.0.0.0" \ 94 | SERVER_PORT="27015" \ 95 | SERVER_CLIENTPORT="27005" \ 96 | SERVER_SOURCETVPORT="27020" \ 97 | SERVER_DEFAULT_MAP="gm_construct" \ 98 | SERVER_MAX_PLAYERS="16" \ 99 | SERVER_TICKRATE="66" \ 100 | SERVER_GAMEMODE="sandbox" \ 101 | SERVER_LOGIN_TOKEN="" \ 102 | SERVER_ADDITIONAL_PARAMETERS="-disableluarefresh" \ 103 | LGSM_DISPLAYIP="" \ 104 | LGSM_POSTALERT="off" \ 105 | LGSM_POSTDAYS="7" \ 106 | LGSM_POSTTARGET="https://hastebin.com" \ 107 | LGSM_DISCORDALERT="off" \ 108 | LGSM_DISCORDWEBHOOK="webhook" \ 109 | LGSM_EMAILALERT="off" \ 110 | LGSM_EMAIL="email@example.com" \ 111 | LGSM_EMAILFROM="" \ 112 | LGSM_IFTTTALERT="off" \ 113 | LGSM_IFTTTTOKEN="accesstoken" \ 114 | LGSM_IFTTTEVENT="linuxgsm_alert" \ 115 | LGSM_MAILGUNALERT="off" \ 116 | LGSM_MAILGUNTOKEN="accesstoken" \ 117 | LGSM_MAILGUNDOMAIN="example.com" \ 118 | LGSM_MAILGUNEMAILFROM="alert@example.com" \ 119 | LGSM_MAILGUNEMAIL="email@myemail.com" \ 120 | LGSM_PUSHBULLETALERT="off" \ 121 | LGSM_PUSHBULLETTOKEN="accesstoken" \ 122 | LGSM_CHANNELTAG="" \ 123 | LGSM_PUSHOVERALERT="off" \ 124 | LGSM_PUSHOVERTOKEN="accesstoken" \ 125 | LGSM_TELEGRAMALERT="off" \ 126 | LGSM_TELEGRAMTOKEN="accesstoken" \ 127 | LGSM_TELEGRAMCHATID="" \ 128 | LGSM_CURLCUSTOMSTRING="" \ 129 | LGSM_UPDATEONSTART="off" \ 130 | LGSM_MAXBACKUPS="4" \ 131 | LGSM_MAXBACKUPDAYS="30" \ 132 | LGSM_STOPONBACKUP="on" \ 133 | LGSM_CONSOLELOGGING="on" \ 134 | LGSM_LOGDAYS="7" \ 135 | LGSM_QUERYDELAY="5" \ 136 | LGSM_BRANCH="" \ 137 | LGSM_STEAMMASTER="true" \ 138 | \ 139 | INSTALL_CSS=false \ 140 | INSTALL_HL2=false \ 141 | INSTALL_HLDM=false \ 142 | INSTALL_TF2=false \ 143 | LGSM_UPDATE=true \ 144 | \ 145 | USE_MY_REPLACER_CONFIG=false 146 | 147 | 148 | COPY ["gmod/prepareServer.sh", "gmod/initConfig.sh", "gmod/forceWorkshopDownload.sh", "gmod/installAndMountAddons.sh", "gmod/common.cfg", "/home/"] 149 | 150 | RUN set -eux; \ 151 | chown "$DOCKER_USER:$DOCKER_USER" /home/prepareServer.sh; \ 152 | chown "$DOCKER_USER:$DOCKER_USER" /home/initConfig.sh; \ 153 | chown "$DOCKER_USER:$DOCKER_USER" /home/forceWorkshopDownload.sh; \ 154 | chown "$DOCKER_USER:$DOCKER_USER" /home/installAndMountAddons.sh; \ 155 | chmod a=rx /home/prepareServer.sh; \ 156 | chmod a=rx /home/initConfig.sh; \ 157 | chmod a=rx /home/forceWorkshopDownload.sh; \ 158 | chmod a=rx /home/installAndMountAddons.sh; \ 159 | \ 160 | /home/createAlias.sh "backup" '/home/steam/gmodserver backup'; \ 161 | /home/createAlias.sh "console" '/home/steam/gmodserver console'; \ 162 | /home/createAlias.sh "debug" '/home/steam/gmodserver debug'; \ 163 | /home/createAlias.sh "details" '/home/steam/gmodserver details'; \ 164 | /home/createAlias.sh "force-update" '/home/steam/gmodserver force-update'; \ 165 | /home/createAlias.sh "install" '/home/steam/gmodserver install'; \ 166 | /home/createAlias.sh "monitor" '/home/steam/gmodserver monitor'; \ 167 | /home/createAlias.sh "postdetails" '/home/steam/gmodserver postdetails'; \ 168 | /home/createAlias.sh "restart" '/home/steam/gmodserver restart'; \ 169 | /home/createAlias.sh "start" '/home/steam/gmodserver start'; \ 170 | /home/createAlias.sh "stop" '/home/steam/gmodserver stop'; \ 171 | /home/createAlias.sh "test-alert" '/home/steam/gmodserver test-alert'; \ 172 | /home/createAlias.sh "update" '/home/steam/gmodserver update'; \ 173 | /home/createAlias.sh "update-lgsm" '/home/steam/gmodserver update-lgsm'; \ 174 | /home/createAlias.sh "validate" '/home/steam/gmodserver validate' 175 | 176 | FROM gmod as TTT 177 | 178 | ENV SERVER_GAMEMODE="terrortown" 179 | 180 | COPY "TTT/server.cfg.default" "/home/server.cfg.default" 181 | 182 | USER "$USER_ID:$GROUP_ID" 183 | 184 | VOLUME "$SERVER_PATH" 185 | -------------------------------------------------------------------------------- /gmod/common.cfg: -------------------------------------------------------------------------------- 1 | ################################## 2 | ######## Default Settings ######## 3 | ################################## 4 | # Copy settings from here and use them in either: 5 | # common.cfg - applies settings to every instance. 6 | # [instance].cfg - applies settings to a specific instance. 7 | if [ "${DEBUGGING}" = "true" ]; then 8 | set -o xtrace 9 | fi 10 | #### Game Server Settings #### 11 | 12 | ## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters 13 | ip="$SERVER_IP" 14 | port="$SERVER_PORT" 15 | clientport="$SERVER_CLIENTPORT" 16 | sourcetvport="$SERVER_SOURCETVPORT" 17 | defaultmap="$SERVER_DEFAULT_MAP" 18 | maxplayers="$SERVER_MAX_PLAYERS" 19 | tickrate="$SERVER_TICKRATE" 20 | gamemode="$SERVER_GAMEMODE" 21 | 22 | ## Workshop Parameters | https://wiki.garrysmod.com/page/Workshop_for_Dedicated_Servers 23 | # To get an API key visit - https://steamcommunity.com/dev/apikey 24 | wsapikey="$WORKSHOP_API_KEY" 25 | wscollectionid="$WORKSHOP_COLLECTION_ID" 26 | 27 | ## Custom Start Parameters 28 | # Default -disableluarefresh, disables lua autorefresh reducing server lag. Auto refresh only useful for developers. 29 | customparms="$SERVER_ADDITIONAL_PARAMETERS" 30 | 31 | ## Optional: Game Server Login Token 32 | # GSLT can be used for running a public server. 33 | # More info: https://linuxgsm.com/gslt 34 | gslt="$SERVER_LOGIN_TOKEN" 35 | 36 | ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters 37 | startparameters="-game garrysmod -strictportbind -ip ${ip} -port ${port} -tickrate ${tickrate} +host_workshop_collection ${wscollectionid} -authkey ${wsapikey} +clientport ${clientport} +tv_port ${sourcetvport} +gamemode ${gamemode} +map ${defaultmap} +sv_setsteamaccount ${gslt} +servercfgfile ${servercfg} -maxplayers ${maxplayers} ${customparms}" 38 | 39 | #### LinuxGSM Settings #### 40 | 41 | ## LinuxGSM Stats 42 | # Send useful stats to LinuxGSM developers. 43 | # https://docs.linuxgsm.com/configuration/linuxgsm-stats 44 | # (on|off) 45 | stats="off" 46 | 47 | ## Notification Alerts 48 | # (on|off) 49 | 50 | # Display IP | https://docs.linuxgsm.com/alerts#display-ip 51 | #shellcheck disable=SC2034 52 | displayip="$LGSM_DISPLAYIP" 53 | 54 | # More info | https://docs.linuxgsm.com/alerts#more-info 55 | #shellcheck disable=SC2034 56 | postalert="$LGSM_POSTALERT" 57 | #shellcheck disable=SC2034 58 | postdays="$LGSM_POSTDAYS" 59 | #shellcheck disable=SC2034 60 | posttarget="$LGSM_POSTTARGET" 61 | 62 | # Discord Alerts | https://docs.linuxgsm.com/alerts/discord 63 | #shellcheck disable=SC2034 64 | discordalert="$LGSM_DISCORDALERT" 65 | #shellcheck disable=SC2034 66 | discordwebhook="$LGSM_DISCORDWEBHOOK" 67 | 68 | # Email Alerts | https://docs.linuxgsm.com/alerts/email 69 | #shellcheck disable=SC2034 70 | emailalert="$LGSM_EMAILALERT" 71 | #shellcheck disable=SC2034 72 | email="$LGSM_EMAIL" 73 | #shellcheck disable=SC2034 74 | emailfrom="$LGSM_EMAILFROM" 75 | 76 | # Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify 77 | gotifyalert="off" 78 | gotifytoken="token" 79 | gotifywebhook="webhook" 80 | 81 | # IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt 82 | #shellcheck disable=SC2034 83 | iftttalert="$LGSM_IFTTTALERT" 84 | #shellcheck disable=SC2034 85 | ifttttoken="$LGSM_IFTTTTOKEN" 86 | #shellcheck disable=SC2034 87 | iftttevent="$LGSM_IFTTTEVENT" 88 | 89 | # Mailgun Email Alerts | https://docs.linuxgsm.com/alerts/mailgun 90 | #shellcheck disable=SC2034 91 | mailgunalert="$LGSM_MAILGUNALERT" 92 | mailgunapiregion="us" 93 | #shellcheck disable=SC2034 94 | mailguntoken="$LGSM_MAILGUNTOKEN" 95 | #shellcheck disable=SC2034 96 | mailgundomain="$LGSM_MAILGUNDOMAIN" 97 | #shellcheck disable=SC2034 98 | mailgunemailfrom="$LGSM_MAILGUNEMAILFROM" 99 | #shellcheck disable=SC2034 100 | mailgunemail="$LGSM_MAILGUNEMAIL" 101 | 102 | # Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet 103 | #shellcheck disable=SC2034 104 | pushbulletalert="$LGSM_PUSHBULLETALERT" 105 | #shellcheck disable=SC2034 106 | pushbullettoken="$LGSM_PUSHBULLETTOKEN" 107 | #shellcheck disable=SC2034 108 | channeltag="$LGSM_CHANNELTAG" 109 | 110 | 111 | # Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover 112 | #shellcheck disable=SC2034 113 | pushoveralert="$LGSM_PUSHOVERALERT" 114 | #shellcheck disable=SC2034 115 | pushovertoken="$LGSM_PUSHOVERTOKEN" 116 | pushoveruserkey="userkey" 117 | 118 | # Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat 119 | rocketchatalert="off" 120 | rocketchatwebhook="webhook" 121 | rocketchattoken="" 122 | 123 | # Slack Alerts | https://docs.linuxgsm.com/alerts/slack 124 | slackalert="off" 125 | slackwebhook="webhook" 126 | 127 | # Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram 128 | # You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". 129 | # For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help". 130 | #shellcheck disable=SC2034 131 | telegramapi="api.telegram.org" 132 | #shellcheck disable=SC2034 133 | telegramalert="$LGSM_TELEGRAMALERT" 134 | #shellcheck disable=SC2034 135 | telegramtoken="$LGSM_TELEGRAMTOKEN" 136 | #shellcheck disable=SC2034 137 | telegramchatid="$LGSM_TELEGRAMCHATID" 138 | #shellcheck disable=SC2034 139 | curlcustomstring="$LGSM_CURLCUSTOMSTRING" 140 | 141 | ## Updating | https://docs.linuxgsm.com/commands/update 142 | #shellcheck disable=SC2034 143 | updateonstart="$LGSM_UPDATEONSTART" 144 | 145 | ## Backup | https://docs.linuxgsm.com/commands/backup 146 | #shellcheck disable=SC2034 147 | maxbackups="$LGSM_MAXBACKUPS" 148 | #shellcheck disable=SC2034 149 | maxbackupdays="$LGSM_MAXBACKUPDAYS" 150 | #shellcheck disable=SC2034 151 | stoponbackup="$LGSM_STOPONBACKUP" 152 | 153 | ## Logging | https://docs.linuxgsm.com/features/logging 154 | #shellcheck disable=SC2034 155 | consolelogging="$LGSM_CONSOLELOGGING" 156 | #shellcheck disable=SC2034 157 | logdays="$LGSM_LOGDAYS" 158 | 159 | ## Monitor | https://docs.linuxgsm.com/commands/monitor 160 | # Query delay time 161 | #shellcheck disable=SC2034 162 | querydelay="$LGSM_QUERYDELAY" 163 | 164 | ## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors 165 | ansi="on" 166 | 167 | #### Advanced Settings #### 168 | 169 | ## Message Display Time | https://docs.linuxgsm.com/features/message-display-time 170 | sleeptime="0.5" 171 | 172 | ## SteamCMD Settings | https://docs.linuxgsm.com/steamcmd 173 | # Server appid 174 | appid="4020" 175 | steamcmdforcewindows="no" 176 | # SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch 177 | branch="$LGSM_BRANCH" 178 | betapassword="" 179 | # Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server 180 | #shellcheck disable=SC2034 181 | steammaster="$LGSM_STEAMMASTER" 182 | 183 | ## Stop Mode | https://docs.linuxgsm.com/features/stop-mode 184 | # 1: tmux kill 185 | # 2: CTRL+c 186 | # 3: quit 187 | # 4: quit 120s 188 | # 5: stop 189 | # 6: q 190 | # 7: exit 191 | # 8: 7 Days to Die 192 | # 9: GoldSrc 193 | # 10: Avorion 194 | # 11: end 195 | stopmode="3" 196 | 197 | ## Query mode 198 | # 1: session only 199 | # 2: gamedig (gsquery fallback) 200 | # 3: gamedig 201 | # 4: gsquery 202 | # 5: tcp 203 | querymode="2" 204 | querytype="protocol-valve" 205 | 206 | ## Console type 207 | consoleverbose="yes" 208 | consoleinteract="yes" 209 | 210 | ## Game Server Details 211 | # Do not edit 212 | gamename="Garry's Mod" 213 | engine="source" 214 | glibc="2.15" 215 | 216 | #### Directories #### 217 | # Edit with care 218 | 219 | ## Game Server Directories 220 | systemdir="${serverfiles}/garrysmod" 221 | addonsdir="${systemdir}/addons" 222 | executabledir="${serverfiles}" 223 | executable="./srcds_run" 224 | servercfgdir="${systemdir}/cfg" 225 | servercfg="${selfname}.cfg" 226 | servercfgdefault="server.cfg" 227 | servercfgfullpath="${servercfgdir}/${servercfg}" 228 | 229 | ## Backup Directory 230 | backupdir="${lgsmdir}/backup" 231 | 232 | ## Logging Directories 233 | logdir="${rootdir}/log" 234 | gamelogdir="${systemdir}/logs" 235 | lgsmlogdir="${logdir}/script" 236 | consolelogdir="${logdir}/console" 237 | lgsmlog="${lgsmlogdir}/${selfname}-script.log" 238 | consolelog="${consolelogdir}/${selfname}-console.log" 239 | alertlog="${lgsmlogdir}/${selfname}-alert.log" 240 | postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" 241 | 242 | ## Logs Naming 243 | lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" 244 | consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GMOD TTT 2 | GMOD TTT server image, https://hub.docker.com/r/jusito/ 3 | 4 | ## Important 5 | If you use the old image, you should check the environment variables. For example arguments after image name aren't used, use instead `-e SERVER_ADDITIONAL_PARAMETERS=...`. 6 | This readme may not be perfect, if you struggle at some point or you see incorrect informations create an issue at git please. 7 | 8 | ## Getting Started 9 | ### Prepare your server content 10 | 1. Create public workshop collection without maps, dummy ID:=123456. Use `-e WORKSHOP_COLLECTION_ID 123456`. 11 | 2. Create public workshop collection with maps and add this one to "123456". 12 | 3. Do you want every user to load the content automatically? Yes you are done, no `-e WORKSHOP_AUTOLOAD=false`. Remember that "false" mean, that every user has to manually subscribe to your collection. If you don't separate maps / others, every connecting user would load all maps on first connecting. This would be a pain for some. 13 | 4. Do your content needs CSS, HL2, HLDM, TF2? Use `-e INSTALL_CSS=true` and/or `-e INSTALL_HL2=true` and so on. Most content will need at least CSS. 14 | 15 | ### Server config 16 | 1. Pick your ports `-e SERVER_PORT=27015 -p 27015:27015/udp` both are always needed. For RCON `[...] -e SERVER_RCON_PASSWORD="verySecure" -p 27015:27015/tcp`. 17 | 2. Set environment variables like servername `-e SERVER_NAME="My Server"`, password `-e SERVER_PASSWORD="securepw"` and timezone for cron `-e TZ="Europe/Berlin"`, default short downtime at Sunday 10 o'clock. 18 | 3. Choose startmap (can be from workshop collection, even linked) `-e SERVER_DEFAULT_MAP=ttt_rooftops_2016_v1` and max players `-e SERVER_MAX_PLAYERS=20` 19 | 4. Get a volume name `-v TTTDev:/home/steam/serverfiles` 20 | 21 | ### run example without rcon 22 | If you need rcon only sometimes, use ulx with this config. 23 | 24 | ``` 25 | docker run -d \ 26 | -p 27015:27015/udp \ 27 | -e SERVER_PORT=27015 \ 28 | -e INSTALL_CSS=true \ 29 | -e WORKSHOP_COLLECTION_ID=123456 \ 30 | -e SERVER_NAME="My Server" \ 31 | -e SERVER_PASSWORD="securepw" \ 32 | -e SERVER_DEFAULT_MAP="ttt_lttp_kakariko_a5" \ 33 | -v TTTDev:/home/steam/serverfiles \ 34 | --name "MyTTTServer" \ 35 | jusito/docker-ttt:gmod_ttt_debian 36 | ``` 37 | 38 | ### run example with rcon 39 | ``` 40 | docker run -d \ 41 | -p 27015:27015/udp \ 42 | -e SERVER_PORT=27015 \ 43 | -e INSTALL_CSS=true \ 44 | -e WORKSHOP_COLLECTION_ID=123456 \ 45 | -e SERVER_NAME="My Server" \ 46 | -e SERVER_PASSWORD="securepw" \ 47 | -e SERVER_DEFAULT_MAP="ttt_lttp_kakariko_a5" \ 48 | -v TTTDev:/home/steam/serverfiles \ 49 | -p 27015:27015/tcp \ 50 | -e SERVER_RCON_PASSWORD="securePW" \ 51 | --name "MyTTTServer" \ 52 | jusito/docker-ttt:gmod_ttt_debian 53 | ``` 54 | 55 | ## Tags 56 | * lgsm\_debian - Linux Game Server Manager in Debian 57 | * gmod\_debian - Garrys Mod with Debian and LGSM 58 | * gmod\_ttt\_debian - Gamemode TTT with LGSM/Debian 59 | 60 | ## Environment Variables 61 | Because you will most likely use many environmental variables, I recommend a env list. Instead of `-e VARNAME="VALUE 1"` write one additional text file: 62 | 63 | TTT.env: 64 | 65 | ``` 66 | VARNAME=Value 1 67 | SERVER_NAME=My Hood 68 | SERVER_PASSWORD=Secure_PW 69 | ``` 70 | ### LGSM Properties 71 | #### Free to change 72 | |Name|Default|Description| 73 | |----|-------|-----------| 74 | |CRON\_MONITOR|"\*/5 \* \* \* \*"|Every 5 minutes LGSM checks if the server is running and responding, rebooting if needed.| 75 | |CRON\_UPDATE|"\*/30 \* \* \* \*"|Every 30 minutes LGSM checks if game server needs an update which will be executed.| 76 | |CRON\_FORCE\_UPDATE|"0 10 \* \* 0"|At Sunday 10:00 force update and restart| 77 | |CRON\_LOG_ROTATE|"0 9 \* \* 0"|Rotate log at Stunday 9:00| 78 | |TZ|Europe/Berlin|[Set timezone for CRON / log](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)| 79 | 80 | #### Used for subimage 81 | |Name|Default|Description| 82 | |----|-------|-----------| 83 | |SERVER_EXECUTABLE|""|Name of the lgsm script after installation| 84 | |SERVER_GAME|""|LGSM name of installation| 85 | 86 | #### LGSM Internal 87 |
LGSM Internal Properties (click me) 88 |

89 | 90 | |Name|Default|Description| 91 | |----|-------|-----------| 92 | |STEAM_PATH|/home/steam|primary workdir, homedir of user| 93 | |SERVER_PATH|/home/steam/serverfiles|Path to serverfiles after installation| 94 | |STEAM_CMD|/home/steam/steamcmd|Path to steamcmd files| 95 | |GROUP_ID|10000|Group ID of the user| 96 | |USER_ID|10000|User ID of the user| 97 | |DOCKER_USER|steam|Name of the user| 98 | |SUPERCRONIC_URL|https://github.com/aptible/supercronic/releases/download/v0.1.9/supercronic-linux-amd64|CRON version| 99 | |SUPERCRONIC|supercronic-linux-amd64|CRON name after download| 100 | |SUPERCRONIC_SHA1SUM|5ddf8ea26b56d4a7ff6faecdd8966610d5cb9d85|CRC for CRON download| 101 | |DEBIAN_FRONTEND|noninteractive|Don't ask questions during installation| 102 | |LANG|C.UTF-8|Language set| 103 | |TERM|xterm|| 104 | |DEBUGGING|false|| 105 | 106 |

107 |
108 | 109 | ### GMOD Properties 110 | #### GMOD Content 111 | |Name|Default|Description| 112 | |----|-------|-----------| 113 | |INSTALL\_CSS|false|Should I install and mount CSS?| 114 | |INSTALL\_HL2|false|Should I install and mount HL2?| 115 | |INSTALL\_HLDM|false|Should I install and mount HLDM?| 116 | |INSTALL\_TF2|false|Should I install and mount TF2?| 117 | |WORKSHOP\_COLLECTION_ID|""|Workshop Collection ID for the server. If you use AUTOLOAD you should add maps on a linked collection| 118 | |WORKSHOP\_API_KEY|""|Maybe needed for private content.| 119 | |WORKSHOP\_AUTOLOAD|true|Every item which is on the given collection, will be downloaded by every client. Elements on linked collections not - so use maps in a linked collection.| 120 | 121 | #### GMOD Server 122 | |Name|Default|Description| 123 | |----|-------|-----------| 124 | |SERVER\_NAME|LinuxGSM|| 125 | |SERVER\_PASSWORD|""|| 126 | |SERVER\_RCON\_PASSWORD|""|| 127 | |SERVER\_VOICE\_ENABLE|1|| 128 | |SERVER\_IP|0.0.0.0|| 129 | |SERVER\_PORT|27015|| 130 | |SERVER\_CLIENTPORT|27005|| 131 | |SERVER\_SOURCETVPORT|27020|| 132 | |SERVER\_DEFAULT\_MAP|gm\_construct|| 133 | |SERVER\_MAX\_PLAYERS|16|| 134 | |SERVER\_TICKRATE|66|| 135 | |SERVER\_GAMEMODE|sandbox|| 136 | |SERVER\_LOGIN\_TOKEN|""|| 137 | |SERVER\_ADDITIONAL\_PARAMETERS|-disableluarefresh|| 138 | 139 | #### GMOD LGSM specific 140 | These variables are untested, but if they dont work report it please too. [Documentation](https://docs.linuxgsm.com/alerts) 141 | 142 | |Name|Default|Description| 143 | |----|-------|-----------| 144 | |LGSM\_DISPLAYIP|""|| 145 | |LGSM\_POSTALERT|off|| 146 | |LGSM\_POSTDAYS|7|| 147 | |LGSM\_POSTTARGET|https://hastebin.com|| 148 | |LGSM\_DISCORDALERT|off|| 149 | |LGSM\_DISCORDWEBHOOK|webhook|| 150 | |LGSM\_EMAILALERT|off|| 151 | |LGSM\_EMAIL|email@example.com|| 152 | |LGSM\_EMAILFROM|""|| 153 | |LGSM\_IFTTTALERT|off|| 154 | |LGSM\_IFTTTTOKEN|accesstoken|| 155 | |LGSM\_IFTTTEVENT|linuxgsm\_alert|| 156 | |LGSM\_MAILGUNALERT|off|| 157 | |LGSM\_MAILGUNTOKEN|accesstoken|| 158 | |LGSM\_MAILGUNDOMAIN|example.com|| 159 | |LGSM\_MAILGUNEMAILFROM|alert@example.com|| 160 | |LGSM\_MAILGUNEMAIL|email@myemail.com|| 161 | |LGSM\_PUSHBULLETALERT|off|| 162 | |LGSM\_PUSHBULLETTOKEN|accesstoken|| 163 | |LGSM\_CHANNELTAG|""|| 164 | |LGSM\_PUSHOVERALERT|off|| 165 | |LGSM\_PUSHOVERTOKEN|accesstoken|| 166 | |LGSM\_TELEGRAMALERT|off|| 167 | |LGSM\_TELEGRAMTOKEN|accesstoken|| 168 | |LGSM\_TELEGRAMCHATID|""|| 169 | |LGSM\_CURLCUSTOMSTRING|""|| 170 | |LGSM\_UPDATEONSTART|off|| 171 | |LGSM\_MAXBACKUPS|4|| 172 | |LGSM\_MAXBACKUPDAYS|30|| 173 | |LGSM\_STOPONBACKUP|on|| 174 | |LGSM\_CONSOLELOGGING|on|| 175 | |LGSM\_LOGDAYS|7|| 176 | |LGSM\_QUERYDELAY|5|| 177 | |LGSM\_BRANCH|""|| 178 | |LGSM\_STEAMMASTER|true"|| 179 | 180 | #### GMOD Internal 181 |
GMOD Internal Properties (click me) 182 |

183 | 184 | |Name|Default|Description| 185 | |----|-------|-----------| 186 | |CSS_PATH|/home/steam/addons/css|| 187 | |HL2_PATH|/home/steam/addons/hl2|| 188 | |HLDM_PATH|/home/steam/addons/hldm|| 189 | |TF2_PATH|/home/steam/addons/tf2|| 190 | |SERVER_EXECUTABLE|gmodserver|| 191 | |SERVER_GAME|gmodserver|| 192 | 193 |

194 |
195 | 196 | ### TTT Properties 197 | #### TTT Internal Properties 198 | |Name|Default|Description| 199 | |----|-------|-----------| 200 | |SERVER_GAMEMODE|"terrortown"|| 201 | 202 | ## LGSM Usage 203 | The container provides links to [LGSM commands](https://docs.linuxgsm.com/commands): 204 | * docker exec -it CONTAINER details // print various informations like passwords, name, players, status aso. 205 | * docker exec -it CONTAINER backup 206 | * docker exec -it CONTAINER console // let you view the current console, docker logs will not work 207 | * docker exec -it CONTAINER debug 208 | * docker exec -it CONTAINER force-update 209 | * docker exec -it CONTAINER install 210 | * docker exec -it CONTAINER monitor 211 | * docker exec -it CONTAINER postdetails 212 | * docker exec -it CONTAINER restart 213 | * docker exec -it CONTAINER start 214 | * docker exec -it CONTAINER stop 215 | * docker exec -it CONTAINER test-alert 216 | * docker exec -it CONTAINER update 217 | * docker exec -it CONTAINER update-lgsm 218 | * docker exec -it CONTAINER validate 219 | 220 | ## File Locations 221 | ### Volumes 222 | /home/steam/serverfiles 223 | 224 | ### Other 225 | server.cfg: /home/steam/serverfiles/garrysmod/cfg/gmodserver.cfg \ 226 | hostname, password, rcon password, voice enabled are managed / will be overwritten 227 | 228 | ## server config 229 | http://ttt.badking.net/config-and-commands/convars 230 | https://wiki.garrysmod.de/server.cfg 231 | 232 | Path in container is: 233 | docker cp "your server.cfg path" CONTAINER:/home/steam/serverfiles/garrysmod/cfg/gmodserver.cfg 234 | 235 | 236 | ## Additional 237 | - Debian Buster, one dependency is missing: https://packages.debian.org/search?keywords=lib32tinfo5 238 | - Alpine, steamcmd doesn't like musl 239 | 240 | ### TODO 241 | #### image improvements 242 | * volume for steam workshop 243 | * volume for other games 244 | * volume for gmod config (data folder) 245 | * AppArmor Profile 246 | 247 | #### image config, description needed 248 | * scrds doesn't like different internal / external ports (thats why no ports are exposed) 249 | * health check -> details 250 | 251 | ### For local usage 252 | navigate to directory with readme.md 253 | bash test/testBuild.sh (sh doesn't like pipefail, escape if you want to use sh) 254 | 255 | 256 | ## FTP Server 257 | * If your Volume is TTTDev 258 | * If you didn't change UserID / GroupID 259 | * If you want to connect to ftp://...:123 (ports 122/123 are free on your network) 260 | 261 | ### For FileZilla 262 | 263 | ``` 264 | docker run -d \ 265 | -e MY_NAME="docker" -e MY_PASSWORD="MySecurePW" \ 266 | -e MY_USER_ID="10000" -e MY_GROUP_ID="10000" \ 267 | -p 122:20 -p 123:21 -p 10090-10100:10090-10100 \ 268 | -v TTTDev:/home/docker/ \ 269 | jusito/vsftpd-alpine:simple 270 | ``` 271 | 272 | ### For Windows Network Mount 273 | * IP of the Host (not container) 1.2.3.4 274 | * Mount: ftp://1.2.3.4:123 275 | 276 | ``` 277 | docker run -d \ 278 | -e MY_NAME="docker" -e MY_PASSWORD="MySecurePW" \ 279 | -e MY_USER_ID="10000" -e MY_GROUP_ID="10000" \ 280 | -p 122:20 -p 123:21 -p 10090-10100:10090-10100 \ 281 | -v TTTDev:/home/docker/ \ 282 | -e pasv_address="1.2.3.4" \ 283 | jusito/vsftpd-alpine:simple 284 | ``` 285 | 286 | ## Synchronize the voice enabled / disabled state with Teamspeak 287 | [See jusito/ttt_voice_sync](https://hub.docker.com/r/jusito/ttt_voice_sync) 288 | --------------------------------------------------------------------------------