diff --git a/.gitignore b/.gitignore index 496ee2c..1db1df5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,11 @@ -.DS_Store \ No newline at end of file +# macOS +.DS_Store + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# Docker +*.log diff --git a/Dockerfile b/Dockerfile index 8e373e6..76c6d36 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ## Pull our base image -FROM debian:12-slim +FROM debian:13-slim ## Image Information LABEL maintainer="Jeff Nelson " @@ -21,14 +21,14 @@ RUN dpkg --add-architecture i386 \ && apt install -y \ curl \ lib32gcc-s1 \ - lib32ncurses5-dev \ + lib32ncurses-dev \ lib32stdc++6 \ lib32z1 \ libc6 \ - libcurl3-gnutls:i386 \ - libncurses5 \ + libcurl3t64-gnutls:i386 \ + libncurses6 \ libsdl2-2.0-0 \ - libtinfo5 \ + libtinfo6 \ unzip \ zlib1g \ && apt clean \ @@ -49,7 +49,7 @@ RUN dpkg --add-architecture i386 \ USER $GAME_USER ## Download SteamCMD -RUN curl -s http://media.steampowered.com/installer/steamcmd_linux.tar.gz | tar -xzC $STEAMCMD_DIR \ +RUN curl -s https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz | tar -xzC $STEAMCMD_DIR \ && $STEAMCMD_DIR/steamcmd.sh \ +login $STEAMCMD_USER $STEAMCMD_PASSWORD $STEAMCMD_AUTH_CODE \ +quit \ @@ -65,5 +65,9 @@ COPY run.sh $APP_DIR/run.sh ## Set working directory WORKDIR $APP_DIR +## Health check to monitor srcds process +HEALTHCHECK --interval=30s --timeout=10s --retries=3 \ + CMD pgrep -f srcds_linux || exit 1 + ## Start the run script CMD ["bash", "run.sh"] \ No newline at end of file diff --git a/build.sh b/build.sh index fde0fb0..d150c8d 100755 --- a/build.sh +++ b/build.sh @@ -1,3 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash +set -e -docker build -t netwarlan/tf2 . +docker build -t ghcr.io/netwarlan/tf2 "$@" . diff --git a/readme.md b/readme.md index 31e53d2..c10ff6d 100644 --- a/readme.md +++ b/readme.md @@ -1,9 +1,12 @@ # Team Fortress 2 - + +[![Docker Build](https://img.shields.io/github/actions/workflow/status/netwarlan/tf2/build.yml?label=build)](https://github.com/netwarlan/tf2/actions) +[![License](https://img.shields.io/github/license/netwarlan/tf2)](LICENSE) + The following repository contains the source files for building a Team Fortress 2 server. +## Running -### Running To run the container, issue the following example command: ``` docker run -d \ @@ -14,7 +17,8 @@ docker run -d \ ghcr.io/netwarlan/tf2 ``` -### Environment Variables +## Environment Variables + We can make dynamic changes to our TF2 containers by adjusting some of the environment variables passed to our image. Below are the ones currently supported and their (defaults): @@ -33,8 +37,33 @@ TF2_SERVER_REMOTE_CFG | No url set TF2_SERVER_ENABLE_PROPHUNT | false TF2_SERVER_CONFIG | server.cfg +## Health Check -### Prop Hunt Setup -A prop hunt server can be stood up by passing the following environment variable `TF2_SERVER_PROPHUNT=true` when starting up the container. +The container includes a built-in health check that monitors the srcds process. Docker will automatically report the container as unhealthy if the game server stops running. + +## Prop Hunt Setup + +A prop hunt server can be stood up by passing the following environment variable `TF2_SERVER_ENABLE_PROPHUNT=true` when starting up the container. This will install MetaMod and SourceMod into the container as well as all the necessary assets like maps, sounds, sourcemod plugins, etc... -*Note: It does appear the TF2 server crashes when attempting to connect to the server for the first time after standing up this type of server. Appears to be a bug, but simply connecting again appears to work fine. No further testing has been done. \ No newline at end of file + +*Note: It does appear the TF2 server crashes when attempting to connect to the server for the first time after standing up this type of server. Appears to be a bug, but simply connecting again appears to work fine. No further testing has been done.* + +## Troubleshooting + +**Server won't start** +- Check Docker logs: `docker logs ` +- Verify all required ports are available and not in use +- Ensure adequate disk space for game files + +**Slow startup** +- First startup downloads ~8GB of game files +- Subsequent startups are faster if game files are persisted via volume + +**Players can't connect** +- Verify ports 27015 UDP/TCP are forwarded/exposed correctly +- Check `TF2_SVLAN` is set to `0` for internet play +- Ensure firewall rules allow incoming connections + +## License + +This project is open source. See the repository for license details. diff --git a/run.sh b/run.sh index a8dd6c6..f50c946 100644 --- a/run.sh +++ b/run.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +set -e echo " @@ -23,18 +24,29 @@ echo " ## Set default values if none were provided ## ============================================== -[[ -z "$TF2_SERVER_PORT" ]] && TF2_SERVER_PORT="27015" -[[ -z "$TF2_SERVER_MAXPLAYERS" ]] && TF2_SERVER_MAXPLAYERS="24" -[[ -z "$TF2_SERVER_MAP" ]] && TF2_SERVER_MAP="ctf_2fort" -[[ -z "$TF2_SVLAN" ]] && TF2_SVLAN="0" -[[ -z "$TF2_SERVER_HOSTNAME" ]] && TF2_SERVER_HOSTNAME="TF2 Server" -[[ ! -z "$TF2_SERVER_PW" ]] && TF2_SERVER_PW="sv_password $TF2_SERVER_PW" -[[ ! -z "$TF2_SERVER_RCONPW" ]] && TF2_SERVER_RCONPW="rcon_password $TF2_SERVER_RCONPW" -[[ -z "$TF2_SERVER_REMOTE_CFG" ]] && TF2_SERVER_REMOTE_CFG="" -[[ -z "$TF2_SERVER_UPDATE_ON_START" ]] && TF2_SERVER_UPDATE_ON_START=true -[[ -z "$TF2_SERVER_VALIDATE_ON_START" ]] && TF2_SERVER_VALIDATE_ON_START=false -[[ -z "$TF2_SERVER_ENABLE_PROPHUNT" ]] && TF2_SERVER_ENABLE_PROPHUNT=false -[[ -z "$TF2_SERVER_CONFIG" ]] && TF2_SERVER_CONFIG="server.cfg" +TF2_SERVER_PORT="${TF2_SERVER_PORT:-27015}" +TF2_SERVER_MAXPLAYERS="${TF2_SERVER_MAXPLAYERS:-24}" +TF2_SERVER_MAP="${TF2_SERVER_MAP:-ctf_2fort}" +TF2_SVLAN="${TF2_SVLAN:-0}" +TF2_SERVER_HOSTNAME="${TF2_SERVER_HOSTNAME:-TF2 Server}" +[[ -n "$TF2_SERVER_PW" ]] && TF2_SERVER_PW="sv_password $TF2_SERVER_PW" +[[ -n "$TF2_SERVER_RCONPW" ]] && TF2_SERVER_RCONPW="rcon_password $TF2_SERVER_RCONPW" +TF2_SERVER_REMOTE_CFG="${TF2_SERVER_REMOTE_CFG:-}" +TF2_SERVER_UPDATE_ON_START="${TF2_SERVER_UPDATE_ON_START:-true}" +TF2_SERVER_VALIDATE_ON_START="${TF2_SERVER_VALIDATE_ON_START:-false}" +TF2_SERVER_ENABLE_PROPHUNT="${TF2_SERVER_ENABLE_PROPHUNT:-false}" +TF2_SERVER_CONFIG="${TF2_SERVER_CONFIG:-server.cfg}" + +## Validate numeric inputs +## ============================================== +if [[ ! "$TF2_SERVER_PORT" =~ ^[0-9]+$ ]]; then + echo "Error: TF2_SERVER_PORT must be a valid number" + exit 1 +fi +if [[ ! "$TF2_SERVER_MAXPLAYERS" =~ ^[0-9]+$ ]]; then + echo "Error: TF2_SERVER_MAXPLAYERS must be a valid number" + exit 1 +fi @@ -81,7 +93,7 @@ EOF ## Download config if needed ## ============================================== -if [[ ! -z "$TF2_SERVER_REMOTE_CFG" ]]; then +if [[ -n "$TF2_SERVER_REMOTE_CFG" ]]; then echo " ╔═══════════════════════════════════════════════╗ ║ Downloading remote config ║ @@ -124,6 +136,7 @@ curl -s ${SOURCEMOD_BASE_URL}/${SOURCEMOD_LATEST} | tar -xzC $GAME_DIR/tf echo "Installing PropHunt Plugins" curl -s ${TF2ITEMS_BUILD_URL} --output /tmp/items.zip unzip -qq -o /tmp/items.zip -d $GAME_DIR/tf +rm -f /tmp/items.zip echo "Installing Maps/Sounds/Configs" mkdir /tmp/prophunt-data