Skip to content

Commit

Permalink
complete factoring to new format with user-jail, steam-user based mea…
Browse files Browse the repository at this point in the history
…ning non-root, added also process exit handler, for clean docker-based-shutdowns
  • Loading branch information
jammsen committed Jan 6, 2025
1 parent e1f0359 commit 7d18703
Show file tree
Hide file tree
Showing 17 changed files with 409 additions and 191 deletions.
File renamed without changes.
32 changes: 32 additions & 0 deletions .github/workflows/docker-build-and-push-refactorbranch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: docker-build-and-push-ci

on:
push:
branches:
- 'refactor-steam-user-jail'

jobs:
docker-build-gameserver-image:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v4
with:
push: true
tags: jammsen/the-forest-dedicated-server:refactor-steam-user-jail
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.idea/
game/
steamcmd/
winedata/
77 changes: 56 additions & 21 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,32 +1,67 @@
FROM jammsen/base:wine-stable-debian-bookworm
FROM cm2network/steamcmd:root AS wine-base

LABEL maintainer="Sebastian Schmidt"
ENV DEBIAN_FRONTEND=noninteractive \
# Path-vars
WINEPREFIX=/wine \
# Container-settings
TIMEZONE=Europe/Berlin

ENV WINEPREFIX=/winedata/WINE64 \
RUN ln -snf /usr/share/zoneinfo/$TIMEZONE /etc/localtime \
&& echo $TIMEZONE > /etc/timezone \
&& dpkg --add-architecture i386 \
&& apt-get update \
&& apt-get install -y --no-install-recommends --no-install-suggests software-properties-common apt-transport-https gnupg2 wget procps winbind xvfb \
&& mkdir -pm755 /etc/apt/keyrings \
&& wget --output-document /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key \
&& wget --timestamping --directory-prefix=/etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/debian/dists/bookworm/winehq-bookworm.sources \
&& apt-get update \
&& apt-get install -y --no-install-recommends --no-install-suggests winehq-stable \
&& apt-get remove -y --purge software-properties-common apt-transport-https gnupg2 wget \
&& apt-get clean \
&& apt-get autoremove -y \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

FROM wine-base AS gameserver

LABEL maintainer="Sebastian Schmidt - https://github.com/jammsen/docker-the-forest-dedicated-server"
LABEL org.opencontainers.image.authors="Sebastian Schmidt"
LABEL org.opencontainers.image.source="https://github.com/jammsen/docker-the-forest-dedicated-server"

SHELL ["/bin/bash", "-o", "pipefail", "-c"]

ENV DEBIAN_FRONTEND=noninteractive \
# Path-vars
GAME_PATH="/theforest" \
GAME_SAVEGAME_PATH="/theforest/saves" \
GAME_CONFIG_PATH="/theforest/config" \
GAME_CONFIGFILE_PATH="/theforest/config/config.cfg" \
STEAMCMD_PATH="/home/steam/steamcmd" \
WINEDATA_PATH="/winedata" \
# Wine/Xvfb-settings
WINEARCH=win64 \
WINEPREFIX="/winedata/WINE64" \
DISPLAY=:1.0 \
# Container-settings
TIMEZONE=Europe/Berlin \
DEBIAN_FRONTEND=noninteractive \
PUID=0 \
PGID=0 \
SERVER_STEAM_ACCOUNT_TOKEN="" \
ALWAYS_UPDATE_ON_START=1

VOLUME ["/theforest", "/steamcmd", "/winedata"]
PUID=1000 \
PGID=1000 \
# SteamCMD-settings
ALWAYS_UPDATE_ON_START=true \
# Gameserver-start-settings-overrides
SERVER_STEAM_ACCOUNT_TOKEN=""

EXPOSE 8766/tcp 8766/udp 27015/tcp 27015/udp 27016/tcp 27016/udp
VOLUME ["${GAME_PATH}", "${STEAMCMD_PATH}", "${WINEDATA_PATH}"]

RUN dpkg --add-architecture i386 \
&& apt-get update \
&& apt-get install -y --no-install-recommends --no-install-suggests lib32gcc-s1 winbind xvfb \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
EXPOSE 8766/udp 27015/udp 27016/udp

COPY ./usr/bin/servermanager.sh /usr/bin/servermanager.sh
COPY ./usr/bin/steamcmdinstaller.sh /usr/bin/steamcmdinstaller.sh
COPY server.cfg.example steamcmdinstall.txt /
COPY --chmod=755 entrypoint.sh /
COPY --chmod=755 scripts/ /scripts
COPY --chmod=755 includes/ /includes
COPY --chmod=644 configs/server.cfg.example /
COPY --chmod=755 gosu-amd64 /usr/local/bin/gosu

RUN ln -snf /usr/share/zoneinfo/$TIMEZONE /etc/localtime \
&& echo $TIMEZONE > /etc/timezone \
&& chmod +x /usr/bin/steamcmdinstaller.sh /usr/bin/servermanager.sh
&& echo $TIMEZONE > /etc/timezone

CMD ["servermanager.sh"]
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/scripts/servermanager.sh"]
59 changes: 36 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,53 +17,66 @@ This includes a TheForest Dedicated Server based on Docker with Wine and an exam
If you are looking for the Sons of the Forest version, please look here:
https://github.com/jammsen/docker-sons-of-the-forest-dedicated-server

## Do you need support for this Docker Image

- What to do?
- Feel free to create a NEW issue
- It is okay to "reference" that you might have the same problem as the person in issue #number
- Follow the instructions and answer the questions of people who are willing to help you
- If your issue is done, close it
- I will Inactivity-Close any issue thats not been active for a week
- What NOT to do?
- Dont re-use issues!
- You are most likely to chat/spam/harrass thoose participants who didnt agree to be part of your / a new problem and might be totally out of context!
- If this happens, i reserve the rights to lock the issue or delete the comments, you have been warned!

## What you need to run this
* Basic understanding of Linux and Docker

## Getting started
WARNING: If you dont do Step 1 and 2 your server can/will not save!
1. Create a new game server account over at https://steamcommunity.com/dev/managegameservers (Use AppID: `242760`)
2. Insert the Login Token into the environment variable via docker-run or docker-compose (at `SERVER_STEAM_ACCOUNT_TOKEN`)
3. Create 2 directories on your Dockernode (`/srv/tfds/steamcmd` and `/srv/tfds/game`)
4. Start the container with the following examples:
3. Go to the directory you want to host your gameserver on your Dockernode
4. Create a sub-directory called `game`
5. Download the [docker-compose.yml](docker-compose.yml) or use the following example
6. Review the file and setup the settings you like
7. Setup Port-Forwarding or NAT for the ports in the Docker-Compose file
8. Start the container via Docker Compose
9. (Tip: Extended config settings, which are not covered by Docker Compose, can be setup in the config-file of the server - You can find it at `game/config/config.cfg`)

### Docker-Compose - Example

Bash:
```console
docker run --rm -i -t -e 'SERVER_STEAM_ACCOUNT_TOKEN=YOUR_TOKEN_HERE' -p 8766:8766/tcp -p 8766:8766/udp -p 27015:27015/tcp -p 27015:27015/udp -p 27016:27016/tcp -p 27016:27016/udp -v /srv/tfds/steamcmd:/steamcmd -v /srv/tfds/game:/theforest --name the-forest-dedicated-server jammsen/the-forest-dedicated-server:latest
or
docker run --rm -i -t -e 'SERVER_STEAM_ACCOUNT_TOKEN=YOUR_TOKEN_HERE' -p 8766:8766/tcp -p 8766:8766/udp -p 27015:27015/tcp -p 27015:27015/udp -p 27016:27016/tcp -p 27016:27016/udp -v $(pwd)/theforest/steamcmd:/steamcmd -v $(pwd)/theforest/game:/theforest --name the-forest-dedicated-server jammsen/the-forest-dedicated-server:latest
```
Docker-Compose:
```yaml
version: "3.7"
version: "3.9"
services:
the-forest-dedicated-server:
container_name: the-forest-dedicated-server
image: jammsen/the-forest-dedicated-server:latest
restart: always
environment:
PUID: 1000
PGID: 1000
ALWAYS_UPDATE_ON_START: true
SERVER_STEAM_ACCOUNT_TOKEN: YOUR_TOKEN_HERE
ALWAYS_UPDATE_ON_START: 1
ports:
- 8766:8766/tcp
- 8766:8766/udp
- 27015:27015/tcp
- 27015:27015/udp
- 27016:27016/tcp
- 27016:27016/udp
volumes:
- ./steamcmd:/steamcmd
- ./game:/theforest
- ./winedata:/winedata
```
## Planned features in the future
Nothing yet
- Feel free to suggest features in the issues
## Software used
* Debian Slim Stable
* Xvfb
* Winbind
* Wine
* SteamCMD
* TheForest Dedicated Server
- Debian Stable and SteamCMD via cm2network/steamcmd:root image as base-image
- gosu
- procps
- winbind
- wine
- xvfb
* TheForest Dedicated Server (APP-ID: 556450)
File renamed without changes.
3 changes: 0 additions & 3 deletions docker-build-and-run.sh

This file was deleted.

10 changes: 4 additions & 6 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
version: "3.7"
version: "3.9"
services:
the-forest-dedicated-server:
container_name: the-forest-dedicated-server
image: jammsen/the-forest-dedicated-server:latest
restart: always
environment:
PUID: 1000
PGID: 1000
ALWAYS_UPDATE_ON_START: true
SERVER_STEAM_ACCOUNT_TOKEN: YOUR_TOKEN_HERE
ports:
- 8766:8766/tcp
- 8766:8766/udp
- 27015:27015/tcp
- 27015:27015/udp
- 27016:27016/tcp
- 27016:27016/udp
volumes:
- ./steamcmd:/steamcmd
- ./game:/theforest
- ./winedata:/winedata
2 changes: 2 additions & 0 deletions docker-run-bash.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
docker run --rm -i -t -p 8766:8766/udp -p 27015:27015/udp -p 27016:27016/udp -v "$(pwd)"/game:/theforest --name the-forest-dedicated-server jammsen/the-forest-dedicated-server:latest bash
5 changes: 2 additions & 3 deletions docker-run.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env bash

docker run --rm -i -t -e 'SERVER_STEAM_ACCOUNT_TOKEN=YOUR_TOKEN_HERE' -p 8766:8766/tcp -p 8766:8766/udp -p 27015:27015/tcp -p 27015:27015/udp -p 27016:27016/tcp -p 27016:27016/udp --name the-forest-dedicated-server jammsen/the-forest-dedicated-server:latest
#docker run --rm -i -t -e 'SERVER_STEAM_ACCOUNT_TOKEN=YOUR_TOKEN_HERE' -p 8766:8766/tcp -p 8766:8766/udp -p 27015:27015/tcp -p 27015:27015/udp -p 27016:27016/tcp -p 27016:27016/udp -v $(pwd)/theforest/steamcmd:/steamcmd -v $(pwd)/theforest/game:/theforest --name the-forest-dedicated-server jammsen/the-forest-dedicated-server:latest
docker run --rm -i -t -e 'SERVER_STEAM_ACCOUNT_TOKEN=YOUR_TOKEN_HERE' -p 8766:8766/udp -p 27015:27015/udp -p 27016:27016/udp -v "$(pwd)"/game:/theforest --name the-forest-dedicated-server jammsen/the-forest-dedicated-server:latest
# docker run --rm -i -t -e 'SERVER_STEAM_ACCOUNT_TOKEN=YOUR_TOKEN_HERE' -p 8766:8766/udp -p 27015:27015/udp -p 27016:27016/udp -v "$(pwd)"/game:/theforest --name the-forest-dedicated-server jammsen/the-forest-dedicated-server:latest
36 changes: 36 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# shellcheck disable=SC1091
# https://stackoverflow.com/questions/27669950/difference-between-euid-and-uid

set -e

APP_USER=steam
APP_GROUP=steam
APP_HOME=/home/$APP_USER

source /includes/colors.sh

if [[ "${EUID}" -ne 0 ]]; then
ee ">>> This Docker-Container must be run as root! Please adjust how you started the container, to fix this error."
exit 1
fi

if [[ "${PUID}" -eq 0 ]] || [[ "${PGID}" -eq 0 ]]; then
ee ">>> Running SOTF as root is not supported, please fix your PUID and PGID!"
exit 1
elif [[ "$(id -u steam)" -ne "${PUID}" ]] || [[ "$(id -g steam)" -ne "${PGID}" ]]; then
ew "> Current $APP_USER user PUID is '$(id -u steam)' and PGID is '$(id -g steam)'"
ew "> Setting new $APP_USER user PUID to '${PUID}' and PGID to '${PGID}'"
groupmod -g "${PGID}" "$APP_GROUP" && usermod -u "${PUID}" -g "${PGID}" "$APP_USER"
else
ew "> Current $APP_USER user PUID is '$(id -u steam)' and PGID is '$(id -g steam)'"
ew "> PUID and PGID matching what is requested for user $APP_USER"
fi

chown -R "$APP_USER":"$APP_GROUP" "$APP_HOME"
chown -R "$APP_USER":"$APP_GROUP" "$GAME_PATH"
chown -R "$APP_USER":"$APP_GROUP" "$WINEDATA_PATH"

ew_nn "> id steam: " ; e "$(id steam)"

exec gosu $APP_USER:$APP_GROUP "$@"
Binary file added gosu-amd64
Binary file not shown.
99 changes: 99 additions & 0 deletions includes/colors.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# shellcheck disable=SC2148
# Idea from https://colors.sh/
# ANSI Color Codes - https://www.shellhacks.com/bash-colors/
# Ansi Default Color Codes https://hyperskill.org/learn/step/18193#terminal-support
# Use ANSI whenever possible. Makes logs compatible with almost all systems.

# Aliases for colorful echos with newlines
function e() {
colorful_echos --base "${@}"
echo ""
}

function ee() {
colorful_echos --error "${@}"
echo ""
}

function ei() {
colorful_echos --info "${@}"
echo ""
}

function es() {
colorful_echos --success "${@}"
echo ""
}

function ew() {
colorful_echos --warning "${@}"
echo ""
}

# Aliases for colorful echos without newlines
function e_nn() {
colorful_echos --base "${@}"
}

function ee_nn() {
colorful_echos --error "${@}"
}

function ei_nn() {
colorful_echos --info "${@}"
}

function es_nn() {
colorful_echos --success "${@}"
}

function ew_nn() {
colorful_echos --warning "${@}"
}

# This creates a wrapper for echo to add colors
function colorful_echos() {
# Set color constants
BASE="\e[97m" # Clean color
CLEAN="\e[0m" # Clean color
ERROR="\e[91m" # Red color for error
INFO="\e[94m" # Blue color for info
SUCCESS="\e[92m" # Green color for success
WARNING="\e[93m" # Yellow color for warning

if [ $# -gt 2 ]; then
echo "Usage: $0 [--success|--error|--info|--warning|--base] <message>"
exit 1
fi

# Parse arguments
arg1=$1
message=$2

# Set color based on argument
if [ "$arg1" == "--success" ]; then
color="$SUCCESS"
elif [ "$arg1" == "--error" ]; then
color="$ERROR"
elif [ "$arg1" == "--info" ]; then
color="$INFO"
elif [ "$arg1" == "--warning" ]; then
color="$WARNING"
elif [ "$arg1" == "--base" ]; then
color="$BASE"
else
echo -ne "$message"
return 0
fi

# print newlines in the beggining of the message
while [ "${message:0:2}" = "\\n" ]; do
# Print a newline
echo ""
# Remove the first two characters from the message
message="${message:2}"
done

# Print message with the specified color
echo -ne "${color}${message}${CLEAN}"
}
Loading

0 comments on commit 7d18703

Please sign in to comment.