From 8e57d68439b3e9c91a8b388169d548677b820224 Mon Sep 17 00:00:00 2001 From: Tahmid Hannan Date: Thu, 5 Feb 2026 18:55:19 -0500 Subject: [PATCH] added features: implement graceful shutdown, tmux wrapper, and healthcheck --- vanilla/Dockerfile | 25 +++++++++-- vanilla/bootstrap.sh | 102 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 102 insertions(+), 25 deletions(-) mode change 100755 => 100644 vanilla/bootstrap.sh diff --git a/vanilla/Dockerfile b/vanilla/Dockerfile index ec4fea0..9c1e783 100755 --- a/vanilla/Dockerfile +++ b/vanilla/Dockerfile @@ -20,6 +20,12 @@ RUN unzip /$DL_FILE -d /terraria && \ FROM debian:trixie-slim ARG TARGETARCH +# adding tmux for the console wrapper and procps for signal handling +RUN apt-get update && apt-get install -y tmux procps && rm -rf /var/lib/apt/lists/* + +# required for tmux to work properly +ENV TERM=xterm + LABEL org.opencontainers.image.authors="Ryan Sheehan " LABEL org.opencontainers.image.url="https://github.com/ryansheehan/terraria" LABEL org.opencontainers.image.documentation="Dockerfile for Terraria" @@ -36,13 +42,19 @@ ENV CONFIGPATH=/config ENV CONFIG_FILENAME="serverconfig.txt" ENV TARGETARCH=${TARGETARCH} +# create the logs directory explicitly +RUN mkdir -p /terraria-server/logs + COPY --from=base /terraria-server/ /terraria-server/ +# fix permissions so we can write to the log file +RUN chmod -R 777 /terraria-server + # Install mono-runtime when building for ARM RUN if [ "${TARGETARCH}" = "arm64" ] || [ "${TARGETARCH}" = "arm" ]; then \ - apt-get update && apt-get install -y ca-certificates mono-runtime && rm -rf /var/lib/apt/lists/*; \ - # The provided system.dll form terraria doesn't match the mono version. - mv /terraria-server/System.dll /usr/lib/mono/4.5/System.dll; \ + apt-get update && apt-get install -y ca-certificates mono-runtime && rm -rf /var/lib/apt/lists/*; \ + # The provided system.dll form terraria doesn't match the mono version. + mv /terraria-server/System.dll /usr/lib/mono/4.5/System.dll; \ fi VOLUME [ "${WORLDPATH}", "${CONFIGPATH}", "${LOGPATH}" ] @@ -50,4 +62,9 @@ VOLUME [ "${WORLDPATH}", "${CONFIGPATH}", "${LOGPATH}" ] # Set working directory to server WORKDIR /terraria-server -ENTRYPOINT [ "/bin/sh", "bootstrap.sh" ] +# check every 30s if the tmux session is still alive +HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ + CMD tmux has-session -t terraria || exit 1 + +# using bash to handle signals better +ENTRYPOINT [ "/bin/bash", "bootstrap.sh" ] \ No newline at end of file diff --git a/vanilla/bootstrap.sh b/vanilla/bootstrap.sh old mode 100755 new mode 100644 index e95536c..3138609 --- a/vanilla/bootstrap.sh +++ b/vanilla/bootstrap.sh @@ -1,38 +1,98 @@ #!/bin/bash +# explicitly set user to root +export USER=root + +# create a tmux config: ctrl+c will detach instead of killing +echo "bind-key -n C-c detach" > /terraria-server/tmux.conf +# ensure session dies when the server exits +echo "set-option -g remain-on-exit off" >> /terraria-server/tmux.conf + +# shutdown logic +cleanup() { + echo "Received Shutdown Signal" + echo "Cleaning buffer and sending 'exit'..." + + # send 'enter' first to clear garbage characters + tmux send-keys -t terraria Enter + sleep 1 + + # send the clean 'exit' command + tmux send-keys -t terraria "exit" Enter + + # wait for the server to close + while tmux has-session -t terraria 2>/dev/null; do + echo "Waiting for server to save and exit..." + tmux capture-pane -pt terraria | tail -n 1 + sleep 2 + done + + echo "Server Saved and Closed Cleanly" + exit 0 +} + +trap 'cleanup' TERM + echo "Bootstrap:" echo "world_file_name=$WORLD_FILENAME" echo "logpath=$LOGPATH" echo "target_arch=$TARGETARCH" - + EXECUTABLE="./TerrariaServer" if [ "$TARGETARCH" = "arm64" ] || [ "$TARGETARCH" = "arm" ]; then - EXECUTABLE="mono ./TerrariaServer.exe" + EXECUTABLE="mono ./TerrariaServer.exe" fi WORLD_PATH="$WORLDPATH/$WORLD_FILENAME" if [ ! -f "$CONFIGPATH/$CONFIG_FILENAME" ]; then - echo "Server configuration not found, running with default server configuration." - echo "Please ensure your desired $CONFIG_FILENAME file is volumed into docker: -v :$CONFIGPATH" - cp ./serverconfig-default.txt $CONFIGPATH/$CONFIG_FILENAME + echo "Server configuration not found, running with default server configuration." + echo "Please ensure your desired $CONFIG_FILENAME file is volumed into docker: -v :$CONFIGPATH" + cp ./serverconfig-default.txt $CONFIGPATH/$CONFIG_FILENAME fi +# variable to capture the command instead of running it directly +SERVER_CMD="" + if [ -z "$WORLD_FILENAME" ]; then - echo "No world file specified in environment WORLD_FILENAME." - if [ -z "$@" ]; then - echo "Running server setup..." - else - echo "Running server with command flags: $@" - fi - $EXECUTABLE -config "$CONFIGPATH/$CONFIG_FILENAME" -logpath "$LOGPATH" "$@" + echo "No world file specified in environment WORLD_FILENAME." + # fixed: checking arg count instead of string content to avoid syntax errors + if [ $# -eq 0 ]; then + echo "Running server setup..." + else + echo "Running server with command flags: $@" + fi + SERVER_CMD="$EXECUTABLE -config \"$CONFIGPATH/$CONFIG_FILENAME\" -logpath \"$LOGPATH\" $@" else - echo "Environment WORLD_FILENAME specified" - if [ -f "$WORLD_PATH" ]; then - echo "Loading to world $WORLD_FILENAME..." - $EXECUTABLE -config "$CONFIGPATH/$CONFIG_FILENAME" -logpath "$LOGPATH" -world "$WORLD_PATH" "$@" - else - echo "Unable to locate $WORLD_PATH." - echo "Please make sure your world file is volumed into docker: -v :$WORLDPATH" - exit 1 - fi + echo "Environment WORLD_FILENAME specified" + if [ -f "$WORLD_PATH" ]; then + echo "Loading to world $WORLD_FILENAME..." + SERVER_CMD="$EXECUTABLE -config \"$CONFIGPATH/$CONFIG_FILENAME\" -logpath \"$LOGPATH\" -world \"$WORLD_PATH\" $@" + else + echo "Unable to locate $WORLD_PATH." + echo "Please make sure your world file is volumed into docker: -v :$WORLDPATH" + exit 1 + fi fi + +echo "Starting Terraria Server in Tmux..." + +# ensure log file exists +touch /terraria-server/server.log + +# start tmux (detached) with custom config and pipe output to log +tmux -f /terraria-server/tmux.conf new-session -d -s terraria "$SERVER_CMD" \; pipe-pane -o -t terraria 'cat > /terraria-server/server.log' + +# start logging in the background so we can see output +tail -f /terraria-server/server.log & +TAIL_PID=$! + +# watchdog loop: wait for the tmux session (server) to finish +# if the server crashes or stops, this loop ends +while tmux has-session -t terraria 2>/dev/null; do + sleep 5 +done + +# if we reach here, the server stopped unexpectedly +echo "Tmux session ended. Stopping container." +kill $TAIL_PID +exit 0 \ No newline at end of file