diff --git a/Dockerfile b/Dockerfile index dbc418f..b503965 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,6 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ php-mysql \ php-curl \ default-mysql-client \ + logrotate \ && rm -rf /var/lib/apt/lists/* # Apache mod_rewrite aktivieren und AllowOverride fuer .htaccess (RemoteCP-Sicherheit) @@ -47,6 +48,10 @@ COPY assets/bin/RunTrackmaniaServer.sh /opt/tmserver/ RUN sed -i 's/\r$//' /opt/tmserver/RunTrackmaniaServer.sh \ && chmod +x /opt/tmserver/RunTrackmaniaServer.sh +COPY assets/bin/XAsecoHealthcheck.sh /opt/tmserver/ +RUN sed -i 's/\r$//' /opt/tmserver/XAsecoHealthcheck.sh \ + && chmod +x /opt/tmserver/XAsecoHealthcheck.sh + COPY assets/bin/AdminServ_v2.1.1.zip /var/www/html RUN unzip /var/www/html/AdminServ_v2.1.1.zip -d /var/www/html \ && rm -f /var/www/html/AdminServ_v2.1.1.zip \ @@ -144,6 +149,11 @@ RUN cp -a /opt/tmserver/xaseco /opt/tmserver/default-xaseco # PHP-Debug-Konfiguration: wird zur Laufzeit vom Startup-Script gesetzt # (kein Rebuild noetig – nur Container neustarten) +# Log-Rotation: logrotate-Konfiguration ins Image kopieren +# Wird zur Laufzeit stuendlich per Background-Loop ausgefuehrt (kein cron noetig). +COPY assets/config/logrotate.conf /etc/logrotate.d/tmserver +RUN chmod 644 /etc/logrotate.d/tmserver + # --- Umgebungsvariablen --- # Sensible Werte (Passwoerter, Keys) werden NICHT im Image hinterlegt, # sondern muessen zur Laufzeit uebergeben werden (z.B. via .env-Datei). @@ -169,6 +179,7 @@ ENV FORCE_CONFIG_UPDATE=false # Spieleinstellungen (MatchSettings) ENV ALLWARMUPDURATION=0 +ENV SHUFFLE_MAPLIST=false # Forced Mods (Skins) - URL zu ZIP-Dateien, die beim Start forciert werden ENV FORCE_MOD_STADIUM="" @@ -191,6 +202,8 @@ ENV XASECO_DB_HOST=mariadb ENV XASECO_DB_NAME=xaseco ENV XASECO_DB_USER=xaseco ENV XASECO_DEDIMANIA_NATION=DEU +ENV XASECO_HEALTHCHECK=true +ENV XASECO_HEALTHCHECK_INTERVAL=60 # Debugging ENV PHP_DISPLAY_ERRORS=false @@ -206,4 +219,8 @@ EXPOSE 2350/udp EXPOSE 3450/tcp EXPOSE 80/tcp +# Graceful Shutdown: SIGTERM wird vom Signal-Handler im Startscript abgefangen +# und alle Dienste (XAseco, TM-Server, Apache) sauber heruntergefahren. +STOPSIGNAL SIGTERM + CMD ["/opt/tmserver/RunTrackmaniaServer.sh"] diff --git a/assets/bin/RunTrackmaniaServer.sh b/assets/bin/RunTrackmaniaServer.sh index c186b21..29094fe 100644 --- a/assets/bin/RunTrackmaniaServer.sh +++ b/assets/bin/RunTrackmaniaServer.sh @@ -368,10 +368,12 @@ fi # ============================================================ # XAseco: TeamSpeak3-Plugin Gateway aktualisieren (fuer bestehende Volumes) # ============================================================ -# Das Original-TS3-Gateway ist nicht mehr verfuegbar. Die eigene -# teamspeak3.xml mit dem Ersatz-Gateway wird in das Volume kopiert, -# falls sie fehlt oder noch das alte (nicht mehr erreichbare) Gateway -# referenziert. Gleichzeitig wird das Plugin reaktiviert, falls es +# Das Original-TS3-Gateway ist nicht mehr verfuegbar. Falls die +# teamspeak3.xml fehlt, wird sie aus dem Template kopiert. Falls sie +# bereits existiert (= Nutzer hat eigene TS3-Daten konfiguriert), +# werden NUR die Gateway-URLs (helperURL/logoURL) gezielt aktualisiert. +# Alle anderen Einstellungen (Server, Port, Channel etc.) bleiben +# erhalten. Gleichzeitig wird das Plugin reaktiviert, falls es # in einer frueheren Version auskommentiert wurde. # ============================================================ XASECO_DIR_TS3="/opt/tmserver/xaseco" @@ -379,16 +381,30 @@ TS3_XML="$XASECO_DIR_TS3/teamspeak3.xml" TS3_DEFAULT="/opt/tmserver/default-xaseco/teamspeak3.xml" TS3_PLUGINS_XML="$XASECO_DIR_TS3/plugins.xml" -# teamspeak3.xml aktualisieren: Kopieren wenn fehlend oder veraltet +# teamspeak3.xml aktualisieren: Kopieren wenn fehlend, Gateway-URLs gezielt patchen +# WICHTIG: Bei bestehender Datei wird NICHT die gesamte Datei ueberschrieben, +# damit benutzerdefinierte Einstellungen (Server, Port, Channel) erhalten bleiben. +# Nur die Gateway-URLs (helperURL/logoURL) werden aktualisiert, falls sie noch +# auf ein altes, nicht mehr erreichbares Gateway zeigen. if [ -f "$TS3_DEFAULT" ]; then if [ ! -f "$TS3_XML" ]; then echo "==> TeamSpeak3-Gateway: teamspeak3.xml fehlt, kopiere aus Template..." cp "$TS3_DEFAULT" "$TS3_XML" echo " teamspeak3.xml erfolgreich kopiert." - elif ! diff -q "$TS3_DEFAULT" "$TS3_XML" > /dev/null 2>&1; then - echo "==> TeamSpeak3-Gateway: teamspeak3.xml wird aktualisiert..." - cp "$TS3_DEFAULT" "$TS3_XML" - echo " teamspeak3.xml erfolgreich aktualisiert." + else + # Gateway-URLs aus dem Template auslesen + NEW_HELPER_URL=$(grep -oP '(?<=).*?(?=)' "$TS3_DEFAULT") + NEW_LOGO_URL=$(grep -oP '(?<=).*?(?=)' "$TS3_DEFAULT") + # Aktuelle URLs aus der bestehenden Datei auslesen + CUR_HELPER_URL=$(grep -oP '(?<=).*?(?=)' "$TS3_XML") + CUR_LOGO_URL=$(grep -oP '(?<=).*?(?=)' "$TS3_XML") + # Nur patchen, wenn sich die Gateway-URLs unterscheiden + if [ "$CUR_HELPER_URL" != "$NEW_HELPER_URL" ] || [ "$CUR_LOGO_URL" != "$NEW_LOGO_URL" ]; then + echo "==> TeamSpeak3-Gateway: Aktualisiere Gateway-URLs (Server-Einstellungen bleiben erhalten)..." + [ -n "$NEW_HELPER_URL" ] && sed -i "s|.*|${NEW_HELPER_URL}|" "$TS3_XML" + [ -n "$NEW_LOGO_URL" ] && sed -i "s|.*|${NEW_LOGO_URL}|" "$TS3_XML" + echo " Gateway-URLs erfolgreich aktualisiert." + fi fi fi @@ -727,6 +743,83 @@ fi echo " Aktive MatchSettings: ${GAME_SETTINGS_PATH}" +# ============================================================ +# MatchSettings: Map-Reihenfolge zufaellig mischen +# ============================================================ +# Ueber die Umgebungsvariable SHUFFLE_MAPLIST kann gesteuert werden, +# ob die Reihenfolge der Maps in der aktiven MatchSettings-Datei +# beim Containerstart zufaellig durchgemischt wird: +# - "false" (Standard): Reihenfolge bleibt unveraendert. +# - "true": Alle -Eintraege werden zufaellig gemischt +# und wird auf 0 gesetzt. +# Die originale Datei wird dabei ueberschrieben. +# ============================================================ + +SHUFFLE_MAPLIST="${SHUFFLE_MAPLIST:-false}" + +if [ "$SHUFFLE_MAPLIST" = "true" ]; then + # Vollstaendigen Pfad zur aktiven MatchSettings-Datei bestimmen + ACTIVE_MS_FILE="$GAMEDATA_DIR/Tracks/${GAME_SETTINGS_PATH}" + if [ -f "$ACTIVE_MS_FILE" ]; then + echo "==> Map-Shuffle: Mische Maps in ${GAME_SETTINGS_PATH}..." + php -r ' + $file = $argv[1]; + $xml = file_get_contents($file); + if ($xml === false) { + echo " FEHLER: Konnte MatchSettings-Datei nicht lesen.\n"; + exit(1); + } + + // Alle ...-Bloecke extrahieren + if (!preg_match_all("/.*?<\/challenge>/s", $xml, $matches)) { + echo " Keine -Eintraege gefunden. Shuffle uebersprungen.\n"; + exit(0); + } + + $challenges = $matches[0]; + $count = count($challenges); + echo " $count Maps gefunden. Mische Reihenfolge...\n"; + + // Zufaellig mischen + shuffle($challenges); + + // Alle bestehenden -Bloecke aus dem XML entfernen + $xmlClean = preg_replace("/(\s*.*?<\/challenge>)+/s", "", $xml, 1); + + // Gemischte Challenges vor wieder einfuegen + $challengeBlock = ""; + foreach ($challenges as $ch) { + $challengeBlock .= "\t" . $ch . "\n"; + } + $xmlNew = str_replace("", $challengeBlock . "", $xmlClean); + + // auf 0 setzen (damit ab der ersten gemischten Map gestartet wird) + $xmlNew = preg_replace("/[^<]*<\/startindex>/", "0", $xmlNew); + + // Datei zurueckschreiben + if (file_put_contents($file, $xmlNew) === false) { + echo " FEHLER: Konnte MatchSettings-Datei nicht schreiben.\n"; + exit(1); + } + + // Erste 3 Maps anzeigen + echo " Reihenfolge erfolgreich gemischt.\n"; + echo " Neue Startreihenfolge (erste 3 Maps):\n"; + for ($i = 0; $i < min(3, $count); $i++) { + if (preg_match("/(.*?)<\/file>/", $challenges[$i], $m)) { + echo " " . ($i + 1) . ". " . $m[1] . "\n"; + } + } + if ($count > 3) echo " ... und " . ($count - 3) . " weitere Maps\n"; + ' "$ACTIVE_MS_FILE" + else + echo "==> Map-Shuffle: MatchSettings-Datei nicht gefunden: ${ACTIVE_MS_FILE}" + echo " Shuffle uebersprungen." + fi +else + echo "==> Map-Shuffle: Deaktiviert (SHUFFLE_MAPLIST=false)." +fi + # Bestimme Server-Modus (Standard: internet) SERVER_MODE="${SERVER_MODE:-internet}" @@ -807,10 +900,22 @@ if [ "$XMLRPC_READY" = "true" ]; then cd /opt/tmserver/xaseco php aseco.php TMN >aseco.log 2>&1 & XASECO_PID=$! + echo "$XASECO_PID" > /tmp/xaseco.pid echo " XAseco gestartet (PID: ${XASECO_PID})" cd /opt/tmserver + + # XAseco Healthcheck / Watchdog starten + XASECO_HEALTHCHECK="${XASECO_HEALTHCHECK:-true}" + if [ "$XASECO_HEALTHCHECK" = "true" ] && [ -f "/opt/tmserver/XAsecoHealthcheck.sh" ]; then + echo "==> Starte XAseco-Healthcheck (Watchdog)..." + /opt/tmserver/XAsecoHealthcheck.sh & + HEALTHCHECK_PID=$! + echo " XAseco-Healthcheck gestartet (PID: ${HEALTHCHECK_PID})" + elif [ "$XASECO_HEALTHCHECK" != "true" ]; then + echo "==> XAseco-Healthcheck ist deaktiviert (XASECO_HEALTHCHECK=${XASECO_HEALTHCHECK})." + fi elif [ "${XASECO_ENABLED:-true}" != "true" ]; then - echo "==> XAseco ist deaktiviert (XASECO_ENABLED=${XASECO_ENABLED})." + echo "==> XAseco ist deaktiviert (XASECO_ENABLED=${XASECO_ENABLED})." fi else echo " WARNUNG: XMLRPC nicht erreichbar - XAseco und Forced Mods wurden NICHT gestartet." @@ -996,5 +1101,293 @@ elif [ "$XMLRPC_READY" = "true" ]; then echo "==> Forced Mods: Keine FORCE_MOD_*-Variablen gesetzt. Ueberspringe." fi +# ============================================================ +# Log-Rotation: Hintergrundprozess starten +# ============================================================ +# logrotate wird stuendlich ausgefuehrt, um Apache-, PHP- und +# XAseco-Logs groessenbasiert zu rotieren (max. 10 MB pro Datei, +# 5 rotierte Dateien). Da im Container kein cron laeuft, wird +# ein einfacher Background-Loop verwendet. +# ============================================================ +echo "==> Starte Log-Rotation (stuendlich, groessenbasiert 10 MB)..." +( + while true; do + sleep 3600 + /usr/sbin/logrotate /etc/logrotate.d/tmserver --state /tmp/logrotate.state + done +) & +LOGROTATE_PID=$! +echo " Log-Rotation gestartet (PID: ${LOGROTATE_PID})" + +# ============================================================ +# Graceful Shutdown: Signal-Handler +# ============================================================ +# Faengt TERM/INT ab und beendet alle Dienste sauber in +# der richtigen Reihenfolge: +# 1. XAseco-Healthcheck (verhindert Neustart waehrend Shutdown) +# 2. XAseco (schliesst DB-Connections ordentlich) +# 3. TrackmaniaServer +# 4. Apache (AdminServ/RemoteCP) +# 5. Log-Rotation +# Verhindert Datenbank-Korruption beim Container-Stop. +# ============================================================ +graceful_shutdown() { + echo "" + echo "============================================================" + echo "==> Graceful Shutdown eingeleitet (Signal empfangen)..." + echo "============================================================" + + # 1. XAseco-Healthcheck beenden (verhindert Neustart waehrend Shutdown) + if [ -n "${HEALTHCHECK_PID:-}" ] && kill -0 "$HEALTHCHECK_PID" 2>/dev/null; then + echo " Beende XAseco-Healthcheck (PID: ${HEALTHCHECK_PID})..." + kill "$HEALTHCHECK_PID" 2>/dev/null + wait "$HEALTHCHECK_PID" 2>/dev/null + echo " XAseco-Healthcheck beendet." + fi + + # 2. XAseco beenden (schliesst DB-Connections ordentlich) + XASECO_PID_CURRENT="" + if [ -f "/tmp/xaseco.pid" ]; then + XASECO_PID_CURRENT=$(cat /tmp/xaseco.pid 2>/dev/null) + fi + if [ -n "$XASECO_PID_CURRENT" ] && kill -0 "$XASECO_PID_CURRENT" 2>/dev/null; then + echo " Beende XAseco (PID: ${XASECO_PID_CURRENT})..." + kill "$XASECO_PID_CURRENT" 2>/dev/null + # Warte max. 10 Sekunden auf sauberes Beenden + WAIT_COUNT=0 + while kill -0 "$XASECO_PID_CURRENT" 2>/dev/null && [ $WAIT_COUNT -lt 10 ]; do + sleep 1 + WAIT_COUNT=$((WAIT_COUNT + 1)) + done + if kill -0 "$XASECO_PID_CURRENT" 2>/dev/null; then + echo " XAseco reagiert nicht, sende SIGKILL..." + kill -9 "$XASECO_PID_CURRENT" 2>/dev/null + fi + echo " XAseco beendet." + rm -f /tmp/xaseco.pid + fi + + # 3. TrackmaniaServer beenden + if [ -n "${TM_PID:-}" ] && kill -0 "$TM_PID" 2>/dev/null; then + echo " Beende TrackmaniaServer (PID: ${TM_PID})..." + kill "$TM_PID" 2>/dev/null + # Warte max. 10 Sekunden auf sauberes Beenden + WAIT_COUNT=0 + while kill -0 "$TM_PID" 2>/dev/null && [ $WAIT_COUNT -lt 10 ]; do + sleep 1 + WAIT_COUNT=$((WAIT_COUNT + 1)) + done + if kill -0 "$TM_PID" 2>/dev/null; then + echo " TrackmaniaServer reagiert nicht, sende SIGKILL..." + kill -9 "$TM_PID" 2>/dev/null + fi + echo " TrackmaniaServer beendet." + fi + + # 4. Apache beenden (AdminServ/RemoteCP) + echo " Beende Apache..." + service apache2 stop 2>/dev/null + echo " Apache beendet." + + # 5. Log-Rotation beenden + if [ -n "${LOGROTATE_PID:-}" ] && kill -0 "$LOGROTATE_PID" 2>/dev/null; then + echo " Beende Log-Rotation (PID: ${LOGROTATE_PID})..." + kill "$LOGROTATE_PID" 2>/dev/null + wait "$LOGROTATE_PID" 2>/dev/null + echo " Log-Rotation beendet." + fi + + echo "============================================================" + echo "==> Graceful Shutdown abgeschlossen." + echo "============================================================" + exit 0 +} + +trap graceful_shutdown TERM INT +echo "==> Signal-Handler registriert (TERM/INT -> Graceful Shutdown)" + +# ============================================================ +# Startup-Zusammenfassung +# ============================================================ +# Gibt am Ende des Startprozesses eine uebersichtliche Box mit +# allen wichtigen Server-Informationen aus. Die Box-Breite passt +# sich automatisch an den laengsten Inhalt an. +# Bei bestehenden Installationen ist dieses Feature nach einem +# Image-Update automatisch aktiv (keine manuellen Schritte noetig). +# ============================================================ +print_startup_summary() { + _SUMMARY_TMP=$(mktemp /tmp/startup_summary.XXXXXX) + + # Map-Anzahl aus aktiver MatchSettings-Datei zaehlen + _ACTIVE_MS_FULL="$GAMEDATA_DIR/Tracks/${GAME_SETTINGS_PATH}" + _MAP_COUNT="0" + if [ -f "$_ACTIVE_MS_FULL" ]; then + _MAP_COUNT=$(grep -c '' "$_ACTIVE_MS_FULL" 2>/dev/null) + _MAP_COUNT=${_MAP_COUNT:-0} + fi + + # MatchSettings-Dateiname extrahieren + _MS_FILENAME=$(basename "$GAME_SETTINGS_PATH") + + # XAseco-Status ermitteln + if [ "${XASECO_ENABLED:-true}" != "true" ]; then + _XASECO_STATUS="Deaktiviert" + elif [ -n "${XASECO_PID:-}" ] && kill -0 "$XASECO_PID" 2>/dev/null; then + _XASECO_STATUS="Aktiv (PID ${XASECO_PID})" + else + _XASECO_STATUS="Nicht gestartet" + fi + + # Healthcheck-Status ermitteln + if [ "${XASECO_ENABLED:-true}" != "true" ]; then + _HC_STATUS="—" + elif [ "${XASECO_HEALTHCHECK:-true}" = "true" ] && [ -n "${HEALTHCHECK_PID:-}" ]; then + _HC_STATUS="Aktiv (PID ${HEALTHCHECK_PID})" + elif [ "${XASECO_HEALTHCHECK:-true}" != "true" ]; then + _HC_STATUS="Deaktiviert" + else + _HC_STATUS="Nicht gestartet" + fi + + # Forced Mods zaehlen + _MOD_COUNT=0 + for _ENV_NAME in FORCE_MOD_STADIUM FORCE_MOD_ISLAND FORCE_MOD_BAY FORCE_MOD_COAST FORCE_MOD_SPEED FORCE_MOD_ALPINE FORCE_MOD_RALLY; do + eval "_MOD_VAL=\${$_ENV_NAME:-}" + [ -n "$_MOD_VAL" ] && _MOD_COUNT=$((_MOD_COUNT + 1)) + done + if [ "$_MOD_COUNT" -gt 0 ]; then + _MODS_STATUS="${_MOD_COUNT} Mod(s) aktiv" + else + _MODS_STATUS="Keine" + fi + + # Shuffle-Status + if [ "${SHUFFLE_MAPLIST:-false}" = "true" ]; then + _SHUFFLE_STATUS="Aktiviert" + else + _SHUFFLE_STATUS="Deaktiviert" + fi + + # Server-Modus-Anzeige + case "${SERVER_MODE:-internet}" in + internet) _MODE_DISPLAY="Internet" ;; + lan) _MODE_DISPLAY="LAN" ;; + *) _MODE_DISPLAY="${SERVER_MODE}" ;; + esac + + # PHP-Debug-Status + if [ "${PHP_DISPLAY_ERRORS:-false}" = "true" ]; then + _PHP_DEBUG="Aktiviert" + else + _PHP_DEBUG="Deaktiviert" + fi + + # Servername aus dedicated_cfg.txt lesen (nicht aus Env-Variable, da diese + # nach AdminServ-Aenderungen oder manuellen Edits veraltet sein kann) + _SERVER_NAME="" + if [ -f "$CONFIG" ]; then + # Nur innerhalb von lesen (nicht aus ) + _SERVER_NAME=$(php -r ' + $cfg = file_get_contents($argv[1]); + if (preg_match("/.*?([^<]*)<\/name>/s", $cfg, $m)) { + echo trim($m[1]); + } + ' "$CONFIG" 2>/dev/null) + fi + _SERVER_NAME=${_SERVER_NAME:-${SERVER_NAME:-Trackmania Server}} + + # Ladder-Modus aus dedicated_cfg.txt lesen + _LADDER_MODE="" + if [ -f "$CONFIG" ]; then + _LADDER_MODE=$(grep -oP '(?<=)[^<]+' "$CONFIG" 2>/dev/null | head -1) + fi + _LADDER_MODE=${_LADDER_MODE:-${SERVER_LADDER_MODE:-forced}} + + # Max-Players und Max-Spectators aus Config lesen (falls verfuegbar) + _MAX_PLAYERS="" + _MAX_SPECS="" + if [ -f "$CONFIG" ]; then + _MAX_PLAYERS=$(grep -oP '(?<=)[^<]+' "$CONFIG" 2>/dev/null | head -1) + _MAX_SPECS=$(grep -oP '(?<=)[^<]+' "$CONFIG" 2>/dev/null | head -1) + fi + _MAX_PLAYERS=${_MAX_PLAYERS:-${SERVER_MAX_PLAYERS:-32}} + _MAX_SPECS=${_MAX_SPECS:-${SERVER_MAX_SPECTATORS:-32}} + + # --- Zeilen in Temp-Datei schreiben ('---' = Trennlinie) --- + cat > "$_SUMMARY_TMP" </ +RemoteCP: http:///remotecp/ +--- +Log-Rotation: Aktiv (stuendlich, max. 10 MB) +PHP-Debug: ${_PHP_DEBUG} +TM-Server: PID ${TM_PID} +EOSUMMARY + + # --- Maximale Zeilenlaenge ermitteln --- + _MAX_LEN=0 + while IFS= read -r _line; do + if [ "$_line" != "---" ]; then + _cur_len=${#_line} + [ "$_cur_len" -gt "$_MAX_LEN" ] && _MAX_LEN=$_cur_len + fi + done < "$_SUMMARY_TMP" + + # Box-Breite: Inhalt + je 2 Zeichen Padding (links/rechts) + _BOX_INNER=$((_MAX_LEN + 4)) + + # --- Horizontale Linie erzeugen --- + _HLINE="" + _i=0 + while [ "$_i" -lt "$_BOX_INNER" ]; do + _HLINE="${_HLINE}═" + _i=$((_i + 1)) + done + + # --- Box ausgeben --- + echo "" + printf '╔%s╗\n' "$_HLINE" + + _is_title=true + while IFS= read -r _line; do + if [ "$_line" = "---" ]; then + printf '╠%s╣\n' "$_HLINE" + elif [ "$_is_title" = "true" ]; then + # Titelzeile zentriert ausgeben + _title_len=${#_line} + _pad_total=$((_MAX_LEN - _title_len)) + _pad_left=$((_pad_total / 2)) + _pad_right=$((_pad_total - _pad_left)) + printf '║ %*s%s%*s ║\n' "$_pad_left" "" "$_line" "$_pad_right" "" + _is_title=false + else + printf '║ %-*s ║\n' "$_MAX_LEN" "$_line" + fi + done < "$_SUMMARY_TMP" + + printf '╚%s╝\n' "$_HLINE" + echo "" + + # Aufraeumen + rm -f "$_SUMMARY_TMP" +} + +print_startup_summary + # Auf TrackmaniaServer warten (Hauptprozess) wait $TM_PID diff --git a/assets/bin/XAsecoHealthcheck.sh b/assets/bin/XAsecoHealthcheck.sh new file mode 100644 index 0000000..70aa443 --- /dev/null +++ b/assets/bin/XAsecoHealthcheck.sh @@ -0,0 +1,182 @@ +#!/bin/sh + +# ============================================================ +# XAseco Healthcheck / Watchdog +# ============================================================ +# Ueberwacht den XAseco-Prozess und startet ihn automatisch +# neu, wenn er abgestuerzt ist oder die Verbindung zum +# TrackmaniaServer verloren hat (kein Overlay mehr sichtbar). +# +# Pruefungen: +# 1) PID-Check: Ist der XAseco-PHP-Prozess noch aktiv? +# 2) XMLRPC-Check: Kann XAseco den TM-Server noch erreichen? +# (Erkennt haengende Prozesse, die das Overlay verloren haben) +# +# Umgebungsvariablen: +# XASECO_HEALTHCHECK - true/false (Standard: true) +# XASECO_HEALTHCHECK_INTERVAL - Pruefintervall in Sekunden (Standard: 60) +# SERVER_XMLRPC_PORT - XMLRPC-Port des TM-Servers (Standard: 5000) +# ============================================================ + +XASECO_DIR="/opt/tmserver/xaseco" +HEALTHCHECK_INTERVAL="${XASECO_HEALTHCHECK_INTERVAL:-60}" +XMLRPC_PORT="${SERVER_XMLRPC_PORT:-5000}" +XASECO_PID_FILE="/tmp/xaseco.pid" +RESTART_COUNT=0 +MAX_CONSECUTIVE_FAILURES=3 +FAILURE_COUNT=0 + +log() { + echo "[XAseco-Healthcheck] $(date '+%Y-%m-%d %H:%M:%S') $1" +} + +# ============================================================ +# XAseco starten und PID speichern +# ============================================================ +start_xaseco() { + cd "$XASECO_DIR" + php aseco.php TMN >aseco.log 2>&1 & + NEW_PID=$! + echo "$NEW_PID" > "$XASECO_PID_FILE" + cd /opt/tmserver + RESTART_COUNT=$((RESTART_COUNT + 1)) + FAILURE_COUNT=0 + log "XAseco gestartet (PID: ${NEW_PID}, Neustart #${RESTART_COUNT})" +} + +# ============================================================ +# Pruefen, ob der XAseco-Prozess noch laeuft +# ============================================================ +check_pid() { + if [ ! -f "$XASECO_PID_FILE" ]; then + return 1 + fi + CURRENT_PID=$(cat "$XASECO_PID_FILE") + if [ -z "$CURRENT_PID" ]; then + return 1 + fi + # Pruefen ob der Prozess existiert und ein PHP-Prozess ist + if kill -0 "$CURRENT_PID" 2>/dev/null; then + return 0 + fi + return 1 +} + +# ============================================================ +# XMLRPC-Verbindungscheck: Pruefen, ob der TM-Server noch +# erreichbar ist (erkennt verlorene Verbindungen) +# ============================================================ +check_xmlrpc_connection() { + php -r ' + $port = (int)$argv[1]; + // Testen ob der XMLRPC-Port noch erreichbar ist + $fp = @fsockopen("127.0.0.1", $port, $errno, $errstr, 5); + if (!$fp) { exit(1); } + + // Handshake lesen + $data = @fread($fp, 4); + if (strlen($data) < 4) { fclose($fp); exit(1); } + $info = unpack("Vsize", $data); + $handshake = @fread($fp, $info["size"]); + if (strpos($handshake, "GBXRemote") === false) { fclose($fp); exit(1); } + + fclose($fp); + exit(0); + ' "$XMLRPC_PORT" 2>/dev/null + return $? +} + +# ============================================================ +# XAseco-Log auf aktuelle Fehler pruefen +# ============================================================ +check_xaseco_log() { + LOG_FILE="$XASECO_DIR/aseco.log" + if [ ! -f "$LOG_FILE" ]; then + return 0 + fi + # Letzte 20 Zeilen auf fatale Fehler / Verbindungsabbrueche pruefen + LAST_LINES=$(tail -20 "$LOG_FILE" 2>/dev/null) + # Typische Fehlermeldungen bei XAseco-Verbindungsverlust + if echo "$LAST_LINES" | grep -qi "connection refused\|broken pipe\|server not responding\|transport error\|socket error\|fatal error"; then + return 1 + fi + return 0 +} + +# ============================================================ +# Hauptschleife: Regelmaeige Ueberwachung +# ============================================================ +log "Watchdog gestartet (Intervall: ${HEALTHCHECK_INTERVAL}s, XMLRPC-Port: ${XMLRPC_PORT})" + +while true; do + sleep "$HEALTHCHECK_INTERVAL" + + # Pruefen ob der TM-Server selbst noch laeuft + if ! check_xmlrpc_connection; then + log "XMLRPC-Port ${XMLRPC_PORT} nicht erreichbar - TM-Server vermutlich beendet. Watchdog stoppt." + break + fi + + NEED_RESTART=false + REASON="" + + # 1) PID-Check: Prozess noch aktiv? + if ! check_pid; then + NEED_RESTART=true + REASON="Prozess nicht mehr aktiv (PID: $(cat "$XASECO_PID_FILE" 2>/dev/null || echo 'unbekannt'))" + fi + + # 2) Log-Check: Fatale Fehler erkannt? + if [ "$NEED_RESTART" = "false" ] && ! check_xaseco_log; then + FAILURE_COUNT=$((FAILURE_COUNT + 1)) + log "WARNUNG: Fehler im XAseco-Log erkannt (${FAILURE_COUNT}/${MAX_CONSECUTIVE_FAILURES})" + if [ "$FAILURE_COUNT" -ge "$MAX_CONSECUTIVE_FAILURES" ]; then + NEED_RESTART=true + REASON="Wiederholte Fehler im Log (${FAILURE_COUNT}x)" + fi + else + # Kein Fehler -> Zaehler zuruecksetzen (nur wenn PID OK) + if [ "$NEED_RESTART" = "false" ]; then + FAILURE_COUNT=0 + fi + fi + + # Neustart durchfuehren + if [ "$NEED_RESTART" = "true" ]; then + log "NEUSTART ERFORDERLICH: ${REASON}" + + # Alten Prozess sicherheitshalber beenden + OLD_PID=$(cat "$XASECO_PID_FILE" 2>/dev/null) + if [ -n "$OLD_PID" ] && kill -0 "$OLD_PID" 2>/dev/null; then + log "Beende haengenden Prozess (PID: ${OLD_PID})..." + kill "$OLD_PID" 2>/dev/null + sleep 3 + # Falls noch aktiv: SIGKILL + if kill -0 "$OLD_PID" 2>/dev/null; then + kill -9 "$OLD_PID" 2>/dev/null + sleep 1 + fi + fi + + # Log rotieren (altes Log sichern fuer Debugging) + if [ -f "$XASECO_DIR/aseco.log" ]; then + TIMESTAMP=$(date '+%Y%m%d_%H%M%S') + cp "$XASECO_DIR/aseco.log" "$XASECO_DIR/aseco_crash_${TIMESTAMP}.log" + log "Crash-Log gesichert: aseco_crash_${TIMESTAMP}.log" + # Maximal 5 Crash-Logs aufbewahren + ls -t "$XASECO_DIR"/aseco_crash_*.log 2>/dev/null | tail -n +6 | xargs rm -f 2>/dev/null + fi + + # Kurz warten, damit evtl. Ressourcen freigegeben werden + sleep 2 + + # XAseco neu starten + start_xaseco + log "XAseco erfolgreich neugestartet." + + # Nach Neustart etwas laenger warten, damit XAseco sich initialisieren kann + sleep 10 + fi +done + +log "Watchdog beendet." diff --git a/assets/config/logrotate.conf b/assets/config/logrotate.conf new file mode 100644 index 0000000..7322f10 --- /dev/null +++ b/assets/config/logrotate.conf @@ -0,0 +1,55 @@ +# ============================================================ +# Log-Rotation fuer tmserver-docker +# ============================================================ +# Wird stuendlich per Background-Loop ausgefuehrt. +# Rotation: groessenbasiert (10 MB), max. 5 rotierte Dateien. +# ============================================================ + +# Apache Access- und Error-Log +/var/log/apache2/access.log +/var/log/apache2/error.log +{ + size 10M + rotate 5 + missingok + notifempty + compress + delaycompress + copytruncate +} + +# PHP Error-Log +/var/log/php_errors.log +{ + size 10M + rotate 5 + missingok + notifempty + compress + delaycompress + copytruncate +} + +# XAseco-Log (liegt im persistenten Volume) +/opt/tmserver/xaseco/aseco.log +{ + size 10M + rotate 5 + missingok + notifempty + compress + delaycompress + copytruncate +} + +# AdminServ-Logs (liegen im persistenten Volume) +/var/www/html/logs/*.log +{ + size 10M + rotate 5 + missingok + notifempty + compress + delaycompress + copytruncate +} diff --git a/docker-compose.yml b/docker-compose.yml index 5a78284..c0fdd9c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,11 @@ services: tmserver: - image: git.techniverse.net/scriptos/trackmania-server:1.2.2 + image: git.techniverse.net/scriptos/trackmania-server:1.3.0 build: context: . container_name: tmserver restart: unless-stopped + stop_grace_period: 30s depends_on: mariadb: condition: service_healthy diff --git a/docs/README.md b/docs/README.md index 0a38fa9..6b9b40d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,7 +9,7 @@ | Dokument | Beschreibung | |----------|-------------| | [Schnellstart](schnellstart.md) | Erste Schritte und minimale Konfiguration | -| [Konfiguration](konfiguration.md) | Persistente Serverkonfiguration (dedicated_cfg.txt) | +| [Konfiguration](konfiguration.md) | Persistente Serverkonfiguration (dedicated_cfg.txt), Graceful Shutdown | | [Umgebungsvariablen](umgebungsvariablen.md) | Alle verfügbaren Umgebungsvariablen | | [Server-Modi](server-modi.md) | LAN- und Internet-Dedicated-Modus | | [AdminServ](adminserv.md) | Einrichtung der Server-Verwaltungsoberfläche | @@ -33,6 +33,7 @@ │ │ │ └── maps-creatematchset.php # MatchSet-Erstellung Script │ │ ├── custom_game_settings.txt # MatchSettings (Spielmodus, Map-Rotation) │ │ ├── dedicated_cfg.txt # Server-Config-Template (mit Platzhaltern) +│ │ ├── logrotate.conf # Log-Rotation-Konfiguration (groessenbasiert) │ │ ├── remotecp/ │ │ │ └── plugins/ │ │ │ ├── CustomPoints/ diff --git a/docs/adminserv.md b/docs/adminserv.md index 364ab89..27c646f 100644 --- a/docs/adminserv.md +++ b/docs/adminserv.md @@ -59,6 +59,8 @@ Alternativ können die PHP-Logs eingesehen werden: docker exec tmserver cat /var/log/php_errors.log ``` +> **Hinweis:** Alle Logs (Apache, PHP, AdminServ) werden automatisch per logrotate rotiert (max. 10 MB pro Datei, 5 rotierte Dateien). Siehe [Konfiguration – Log-Rotation](konfiguration.md#log-rotation). + ### AdminServ komplett zurücksetzen Falls AdminServ in einen inkonsistenten Zustand geraten ist: diff --git a/docs/konfiguration.md b/docs/konfiguration.md index 72e0d49..b5ddca0 100644 --- a/docs/konfiguration.md +++ b/docs/konfiguration.md @@ -106,6 +106,105 @@ Der Ordner `GameData/Config/` enthält: | `Default.SystemConfig.Gbx` | System-Konfiguration | | `AdminServ/ServerOptions/` | Von AdminServ exportierte Server-Einstellungen | +## Graceful Shutdown + +Beim Stoppen des Containers (`docker compose stop`, `docker compose down` oder `docker stop`) werden alle Dienste **sauber und in der richtigen Reihenfolge** heruntergefahren: + +1. **XAseco-Healthcheck** – wird zuerst beendet, damit XAseco nicht während des Shutdowns neu gestartet wird +2. **XAseco** – beendet sich ordentlich und schließt alle Datenbank-Connections (verhindert DB-Korruption) +3. **TrackmaniaServer** – der Spielserver wird sauber gestoppt +4. **Apache** – AdminServ und RemoteCP werden beendet +5. **Log-Rotation** – Hintergrundprozess wird gestoppt + +Jeder Dienst hat maximal 10 Sekunden Zeit, sich sauber zu beenden. Falls ein Prozess nicht reagiert, wird er zwangsweise beendet (SIGKILL). Die `stop_grace_period` in der `docker-compose.yml` ist auf 30 Sekunden gesetzt, um genügend Zeit für den gesamten Shutdown-Prozess zu geben. + +Der Shutdown-Fortschritt wird in der Konsole protokolliert und kann mit `docker logs tmserver` nachvollzogen werden. + +> **Hinweis:** Der Graceful Shutdown ist nach einem Image-Update automatisch aktiv – auch bei bestehenden Installationen. Es sind keine manuellen Schritte nötig. + +## Log-Rotation + +Alle Log-Dateien im Container werden automatisch per `logrotate` rotiert, damit sie nicht unbegrenzt wachsen. Die Rotation läuft **größenbasiert** als Hintergrundprozess (stündliche Prüfung, kein Cron nötig). + +### Einstellungen + +| Parameter | Wert | +|-----------|------| +| Maximale Dateigröße | 10 MB | +| Rotierte Dateien behalten | 5 | +| Komprimierung | Ja (gzip, verzögert) | +| Leere Logs überspringen | Ja | + +### Rotierte Log-Dateien + +| Log | Pfad im Container | Persistenz | +|-----|--------------------|------------| +| Apache Access | `/var/log/apache2/access.log` | Nur im Container | +| Apache Error | `/var/log/apache2/error.log` | Nur im Container | +| PHP Errors | `/var/log/php_errors.log` | Nur im Container | +| XAseco | `/opt/tmserver/xaseco/aseco.log` | Volume (`./data/xaseco/`) | +| AdminServ | `/var/www/html/logs/*.log` | Volume (`./data/controlpanel/logs/`) | + +Rotierte Dateien werden als `*.1` (vorherige), `*.2.gz`, `*.3.gz` usw. aufbewahrt. + +### Konfigurationsdatei + +Die logrotate-Konfiguration liegt im Image unter `/etc/logrotate.d/tmserver` (Quelle: `assets/config/logrotate.conf`). Sie wird beim Bau des Images fest eingebettet und erfordert keine manuelle Anpassung. + +> **Hinweis:** Die Log-Rotation ist nach einem Image-Update automatisch aktiv – auch bei bestehenden Installationen. Es sind keine manuellen Schritte nötig. + +## Startup-Zusammenfassung + +Nach Abschluss des gesamten Startprozesses wird automatisch eine übersichtliche Zusammenfassung aller wichtigen Server-Informationen als formatierte Box in der Konsole ausgegeben. Die Box-Breite passt sich dynamisch an den längsten Inhalt an. + +Alle angezeigten Werte (Servername, Spielerzahl, Ladder-Modus etc.) werden direkt aus der `dedicated_cfg.txt` gelesen – nicht aus den Umgebungsvariablen. So werden auch nachträgliche Änderungen (z.B. über AdminServ oder manuelles Editieren) korrekt angezeigt. + +**Angezeigte Informationen:** + +| Bereich | Details | Quelle | +|---------|---------|--------| +| **Server** | Servername, Modus (Internet/LAN), Ladder, Spieler-/Zuschauerlimit | `dedicated_cfg.txt` | +| **Netzwerk** | Server-Port, P2P-Port, XMLRPC-Port | Umgebungsvariablen | +| **Maps** | Aktive MatchSettings-Datei, Anzahl geladener Maps, Shuffle-Status | MatchSettings-XML | +| **Dienste** | XAseco-Status (mit PID), Healthcheck, Forced Mods | Laufzeit-PIDs | +| **Web-Interfaces** | AdminServ- und RemoteCP-URLs | Platzhalter | +| **System** | Log-Rotation, PHP-Debug-Modus, TM-Server-PID | Laufzeit | + +**Beispielausgabe:** + +``` +╔════════════════════════════════════════════════════════════════════╗ +║ TrackMania Nations Forever - Server gestartet ║ +╠════════════════════════════════════════════════════════════════════╣ +║ Servername: Mein Trackmania Server ║ +║ Modus: Internet (Ladder: forced) ║ +║ Spieler: max. 32 Spieler / 32 Zuschauer ║ +║ Server-Port: 2350 (TCP/UDP) | P2P: 3450 (TCP) ║ +║ XMLRPC-Port: 5000 ║ +╠════════════════════════════════════════════════════════════════════╣ +║ MatchSettings: custom_game_settings.txt ║ +║ Maps: 24 Maps geladen ║ +║ Map-Shuffle: Deaktiviert ║ +╠════════════════════════════════════════════════════════════════════╣ +║ XAseco: Aktiv (PID 1234) ║ +║ Healthcheck: Aktiv (PID 5678) ║ +║ Forced Mods: Keine ║ +╠════════════════════════════════════════════════════════════════════╣ +║ AdminServ: http:/// ║ +║ RemoteCP: http:///remotecp/ ║ +╠════════════════════════════════════════════════════════════════════╣ +║ Log-Rotation: Aktiv (stuendlich, max. 10 MB) ║ +║ PHP-Debug: Deaktiviert ║ +║ TM-Server: PID 42 ║ +╚════════════════════════════════════════════════════════════════════╝ +``` + +Die Zusammenfassung kann jederzeit mit `docker logs tmserver` erneut eingesehen werden. + +> **Hinweis:** `` ist ein Platzhalter – ersetze ihn durch die tatsächliche IP oder Domain deines Hosts (z.B. `http://192.168.1.100/`). + +> **Hinweis:** Die Startup-Zusammenfassung ist nach einem Image-Update automatisch aktiv – auch bei bestehenden Installationen. Es sind keine manuellen Schritte nötig. + ## AdminServ ServerOptions-Import Wenn über AdminServ Änderungen an den Server-Optionen vorgenommen und als Export gespeichert werden (z.B. Servername, Beschreibung, Spielerzahl), werden diese beim nächsten Container-Start **automatisch** in die `dedicated_cfg.txt` übernommen. diff --git a/docs/schnellstart.md b/docs/schnellstart.md index 496b813..02ae590 100644 --- a/docs/schnellstart.md +++ b/docs/schnellstart.md @@ -43,10 +43,10 @@ Die Konfiguration erfolgt über die `.env`-Datei, die automatisch eingelesen wir Alternativ kannst du das Image auch selbst bauen: ```bash -docker build -t tmserver:latest -t tmserver:1.2.1 . +docker build -t tmserver:latest -t tmserver:1.3.0 . ``` -Damit wird das Image mit zwei Tags erstellt: `tmserver:latest` und `tmserver:1.2.1`. +Damit wird das Image mit zwei Tags erstellt: `tmserver:latest` und `tmserver:1.3.0`. Anschließend den Server starten: diff --git a/docs/umgebungsvariablen.md b/docs/umgebungsvariablen.md index c439ea4..fb499eb 100644 --- a/docs/umgebungsvariablen.md +++ b/docs/umgebungsvariablen.md @@ -73,6 +73,7 @@ nano .env |----------|-------------|----------| | `MATCHSETTINGS_FILE` | MatchSettings-Datei beim Serverstart: `auto` = neueste `.txt`-Datei im Ordner wird automatisch geladen, oder ein expliziter Dateiname (z.B. `meine_settings.txt`) | `auto` | | `ALLWARMUPDURATION` | Warmup-Dauer für alle Runden (`0` = deaktiviert, `1` = eine Runde Warmup) | `0` | +| `SHUFFLE_MAPLIST` | Map-Reihenfolge beim Containerstart zufällig mischen (`true` = aktiviert, `false` = deaktiviert) | `false` | ### Automatische MatchSettings-Erkennung @@ -90,6 +91,27 @@ MATCHSETTINGS_FILE=turnier_settings.txt > **Hinweis:** Falls die angegebene oder automatisch ermittelte Datei nicht existiert, wird auf `custom_game_settings.txt` zurückgefallen. Die aktiv geladene Datei wird beim Serverstart in der Konsole ausgegeben. +### Map-Shuffle + +Mit `SHUFFLE_MAPLIST=true` wird die Reihenfolge aller Maps in der aktiven MatchSettings-Datei beim **jedem Containerstart** zufällig durchgemischt. So startet der Server jedes Mal mit einer anderen Map, statt immer bei Map #1 zu beginnen. + +- Die ``-Einträge in der MatchSettings-XML werden zufällig neu angeordnet +- Der `` wird automatisch auf `0` gesetzt +- Die aktive MatchSettings-Datei wird dabei direkt überschrieben +- Die ersten 3 Maps der neuen Reihenfolge werden beim Start in der Konsole angezeigt + +**Beispiel:** + +```bash +# Map-Reihenfolge bei jedem Start mischen +SHUFFLE_MAPLIST=true + +# Deaktiviert (Standard) – Reihenfolge bleibt wie in der Datei +SHUFFLE_MAPLIST=false +``` + +> **Hinweis:** Der Shuffle wird auf die MatchSettings-Datei angewendet, die durch `MATCHSETTINGS_FILE` bestimmt wird (entweder automatisch oder explizit). Die Änderung ist persistent – die Datei wird tatsächlich umgeschrieben. Bei jedem Neustart wird erneut gemischt. + ## RemoteCP RemoteCP verwendet die SuperAdmin-Zugangsdaten (`SERVER_SA_PASSWORD`) des TM-Servers für den Web-Login. Es werden keine separaten Login-Variablen benötigt. @@ -161,6 +183,8 @@ XAseco ist ein Server-Controller für Rekorde, Karma, Jukebox und mehr. Siehe [X | `XASECO_DB_USER` | Datenbank-Benutzername | `xaseco` | | `XASECO_DB_PASSWORD` | Datenbank-Passwort | *(muss gesetzt werden)* | | `XASECO_DEDIMANIA_NATION` | Dedimania-Nation (IOC-Code) | `DEU` | +| `XASECO_HEALTHCHECK` | Automatische Überwachung und Neustart von XAseco bei Absturz/Verbindungsverlust | `true` | +| `XASECO_HEALTHCHECK_INTERVAL` | Prüfintervall des Healthchecks in Sekunden | `60` | > **Hinweis:** Die Server-Zugangsdaten (`SERVER_SA_PASSWORD`, `SERVER_XMLRPC_PORT`) und Dedimania-Daten (`SERVER_LOGIN`, `SERVER_LOGIN_PASSWORD`) werden automatisch aus der bestehenden Konfiguration übernommen. diff --git a/docs/xaseco.md b/docs/xaseco.md index 3b82278..df2384a 100644 --- a/docs/xaseco.md +++ b/docs/xaseco.md @@ -77,6 +77,8 @@ Die Konfiguration erfolgt ausschließlich über Umgebungsvariablen in der `.env` | `XASECO_DB_NAME` | Name der XAseco-Datenbank | `xaseco` | | `XASECO_DB_USER` | Datenbank-Benutzername | `xaseco` | | `XASECO_DEDIMANIA_NATION` | Dedimania-Nation ([IOC-Code](https://en.wikipedia.org/wiki/List_of_IOC_country_codes), z.B. `DEU`, `AUT`, `CHE`) | `DEU` | +| `XASECO_HEALTHCHECK` | Automatische Überwachung und Neustart bei Absturz | `true` | +| `XASECO_HEALTHCHECK_INTERVAL` | Prüfintervall des Healthchecks in Sekunden | `60` | ### Automatisch übernommene Variablen @@ -147,6 +149,37 @@ XASECO_ENABLED=false Der TrackMania-Server läuft dann ohne Server-Controller. +## Healthcheck / Watchdog + +XAseco wird automatisch durch einen Watchdog-Prozess überwacht. Dieser erkennt Abstürze und verlorene Verbindungen (z.B. wenn das Overlay im Spiel verschwindet) und startet XAseco selbstständig neu. + +### Funktionsweise + +Der Watchdog prüft regelmäßig (Standard: alle 60 Sekunden): + +1. **PID-Check:** Läuft der XAseco-PHP-Prozess noch? +2. **Log-Check:** Enthält das XAseco-Log fatale Fehler oder Verbindungsabbrüche? +3. **XMLRPC-Check:** Ist der TM-Server noch erreichbar? + +Bei erkannten Problemen wird XAseco automatisch beendet und neu gestartet. Crash-Logs werden zur Fehleranalyse unter `data/xaseco/aseco_crash_.log` gesichert (max. 5 Dateien). + +### Konfiguration + +| Variable | Beschreibung | Standard | +|----------|-------------|----------| +| `XASECO_HEALTHCHECK` | Watchdog aktivieren/deaktivieren | `true` | +| `XASECO_HEALTHCHECK_INTERVAL` | Prüfintervall in Sekunden | `60` | + +```env +# Healthcheck deaktivieren +XASECO_HEALTHCHECK=false + +# Prüfintervall auf 30 Sekunden verkürzen +XASECO_HEALTHCHECK_INTERVAL=30 +``` + +> **Hinweis:** Der Watchdog ist standardmäßig aktiviert und erfordert keine zusätzliche Konfiguration. Bei bestehenden Installationen wird er nach dem nächsten Image-Update automatisch aktiv. + ## Logs Die XAseco-Logdatei befindet sich unter: @@ -157,6 +190,8 @@ Die XAseco-Logdatei befindet sich unter: Bei Problemen ist dies die erste Anlaufstelle für die Fehlersuche. +> **Hinweis:** Die XAseco-Logdatei wird automatisch per logrotate rotiert (max. 10 MB pro Datei, 5 rotierte Dateien). Alte Logs werden komprimiert als `aseco.log.1.gz`, `aseco.log.2.gz` usw. aufbewahrt. Siehe [Konfiguration – Log-Rotation](konfiguration.md#log-rotation). + ## Chat-Befehle Nachfolgend eine Übersicht der wichtigsten Befehle, die im Spielchat verfügbar sind. Eine vollständige Liste aller Befehle findest du in der offiziellen Dokumentation unter: https://docs.xaseco.org/commands.php