├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml └── workflows │ ├── auto-merge-master-to-develop.yml │ ├── docker-build-and-push-develop.yml │ ├── docker-build-and-push-prod.yml │ └── unit-test.yml ├── .gitignore ├── CHANGELOG.md ├── Dockerfile ├── README.md ├── configs ├── dedicatedserver.cfg.example ├── ownerswhitelist.txt.example └── steam_appid.txt ├── docker-build.sh ├── docker-compose.yml ├── docker-exec.sh ├── docker-run-bash.sh ├── docker-run.sh ├── entrypoint.sh ├── gosu-amd64 ├── includes └── colors.sh └── scripts └── servermanager.sh /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: "🐞 Bug report" 2 | description: Create a bug report to help us improve things 3 | labels: ["bug"] 4 | title: "[Bug Report] Your descriptive title here!" 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | ## Important information 10 | Please understand you are asking for support for the Docker-Image and Docker-Container. I'm NOT the creator of the Dedicated-Game-Server itself, i'm not involved in programming that. If you need help for that, you might want to ask here for topics related to that: https://steamcommunity.com/app/1326470/discussions/0/3808404524164518482/ 11 | - type: checkboxes 12 | id: understand-important-info 13 | attributes: 14 | label: Have you read the Important information text above 15 | options: 16 | - label: Yes i did 17 | required: true 18 | - type: textarea 19 | id: current-behavior 20 | attributes: 21 | label: Current behavior 22 | description: A clear and concise description of what the problem is. 23 | placeholder: Currently... 24 | validations: 25 | required: true 26 | - type: textarea 27 | id: desired-behavior 28 | attributes: 29 | label: Desired behavior 30 | description: Remember, im not familiar with your setup, your permission, your Docker settings and all that kind of stuff, please provide a clear description of what your desired outcome is. 31 | placeholder: Desried ... 32 | validations: 33 | required: true 34 | - type: textarea 35 | id: screenshot-links 36 | attributes: 37 | label: Links to screenshots 38 | placeholder: ... 39 | validations: 40 | required: false 41 | - type: textarea 42 | id: reproduction 43 | attributes: 44 | label: To Reproduce 45 | description: What steps can i do to reproduce your problem? 46 | value: | 47 | Steps to reproduce the behavior: 48 | 1. Go to '...' 49 | 2. Click on '....' 50 | 3. Scroll down to '....' 51 | 4. See error 52 | validations: 53 | required: true 54 | - type: textarea 55 | id: software 56 | attributes: 57 | label: Software setup 58 | value: | 59 | - OS: 60 | - Docker: 61 | validations: 62 | required: true 63 | - type: textarea 64 | id: hardware 65 | attributes: 66 | label: Hardware setup 67 | value: | 68 | - vCPU: 69 | - RAM: 70 | - Disk: 71 | validations: 72 | required: true 73 | - type: textarea 74 | id: more 75 | attributes: 76 | label: Additional context 77 | placeholder: Add any other context about the problem here, in as much detail as possible. 78 | validations: 79 | required: false 80 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: "🚀 Feature request" 2 | description: Suggest a feature that will improve things 3 | labels: ["enhancement"] 4 | title: "[Feature Request] Your descriptive title here!" 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | ## Important information 10 | Thank you for taking the time to fill out this feature request! Please understand you are asking for support for the Docker-Image and Docker-Container. I'm NOT the creator of the Dedicated-Game-Server itself, i'm not involved in programming that. If you need help for that, you might want to ask here for topics related to that: https://steamcommunity.com/app/1326470/discussions/0/3808404524164518482/ 11 | - type: checkboxes 12 | id: understand-important-info 13 | attributes: 14 | label: Have you read the Important information text above 15 | options: 16 | - label: Yes i did 17 | required: true 18 | - type: textarea 19 | id: feature-description 20 | attributes: 21 | label: Describe the feature 22 | description: A clear and concise description of what you think would be a helpful addition, including the possible use cases and alternatives you have considered. If you have a working prototype or something similar, please include a link. 23 | placeholder: Feature description 24 | validations: 25 | required: true 26 | - type: checkboxes 27 | id: additional-info 28 | attributes: 29 | label: Additional information 30 | description: Additional information that helps us decide how to proceed. 31 | options: 32 | - label: Would you be willing to help implement this feature? 33 | - type: checkboxes 34 | id: required-info 35 | attributes: 36 | label: Final checks 37 | description: Before submitting, please understand and agree to this 38 | options: 39 | - label: I understand that this is a feature request function. I also understand that if i use this to report a bug report, that my issue might be un-answered closed. 40 | required: true -------------------------------------------------------------------------------- /.github/workflows/auto-merge-master-to-develop.yml: -------------------------------------------------------------------------------- 1 | name: Pull request to master 2 | on: 3 | pull_request: 4 | branches: [master] 5 | types: [closed] 6 | jobs: 7 | merge-master-back-to-dev: 8 | if: github.event.pull_request.merged == true 9 | timeout-minutes: 1 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Set Git config 14 | run: | 15 | git config --local user.email "actions@github.com" 16 | git config --local user.name "Github Actions" 17 | - name: Merge master back to dev 18 | run: | 19 | git fetch --unshallow 20 | git checkout develop 21 | git pull 22 | git merge --no-ff master -m "Auto-merge master back to dev" 23 | git push -------------------------------------------------------------------------------- /.github/workflows/docker-build-and-push-develop.yml: -------------------------------------------------------------------------------- 1 | name: docker-build-and-push-develop-ci 2 | 3 | on: 4 | workflow_run: 5 | workflows: 6 | - Unit-test # Wait for the "Unit-test" workflow to complete 7 | types: 8 | - completed # Trigger only when "Unit-test" completes 9 | 10 | jobs: 11 | docker-build-gameserver-image: 12 | if: ${{ github.event.workflow_run.conclusion == 'success' && github.ref == 'refs/heads/develop' }} # Run only if tests pass and branch is "develop" 13 | runs-on: ubuntu-latest 14 | steps: 15 | - 16 | name: Checkout 17 | uses: actions/checkout@v3 18 | - 19 | name: Set up QEMU 20 | uses: docker/setup-qemu-action@v2 21 | - 22 | name: Set up Docker Buildx 23 | uses: docker/setup-buildx-action@v2 24 | - 25 | name: Login to Docker Hub 26 | uses: docker/login-action@v2 27 | with: 28 | username: ${{ secrets.DOCKERHUB_USERNAME }} 29 | password: ${{ secrets.DOCKERHUB_TOKEN }} 30 | - 31 | name: Build and push 32 | uses: docker/build-push-action@v4 33 | with: 34 | push: true 35 | tags: jammsen/sons-of-the-forest-dedicated-server:develop 36 | -------------------------------------------------------------------------------- /.github/workflows/docker-build-and-push-prod.yml: -------------------------------------------------------------------------------- 1 | name: docker-build-and-push-master-ci 2 | 3 | on: 4 | workflow_run: 5 | workflows: 6 | - Unit-test # Wait for the "Unit-test" workflow to complete 7 | types: 8 | - completed # Trigger only when "Unit-test" completes 9 | 10 | jobs: 11 | docker-build-gameserver-image: 12 | if: ${{ github.event.workflow_run.conclusion == 'success' && github.ref == 'refs/heads/master' }} # Run only if tests pass and branch is "develop" 13 | runs-on: ubuntu-latest 14 | steps: 15 | - 16 | name: Checkout 17 | uses: actions/checkout@v3 18 | - 19 | name: Set up QEMU 20 | uses: docker/setup-qemu-action@v2 21 | - 22 | name: Set up Docker Buildx 23 | uses: docker/setup-buildx-action@v2 24 | - 25 | name: Login to Docker Hub 26 | uses: docker/login-action@v2 27 | with: 28 | username: ${{ secrets.DOCKERHUB_USERNAME }} 29 | password: ${{ secrets.DOCKERHUB_TOKEN }} 30 | - 31 | name: Build and push 32 | uses: docker/build-push-action@v4 33 | with: 34 | push: true 35 | tags: jammsen/sons-of-the-forest-dedicated-server:latest 36 | -------------------------------------------------------------------------------- /.github/workflows/unit-test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Unit-test 3 | on: 4 | push: 5 | branches: 6 | - develop # Run tests on commit to the develop branch 7 | - master # Run tests on commit to the master branch 8 | pull_request: # Run tests on all pull requests 9 | workflow_call: # Allow this workflow to be called by other workflows 10 | 11 | concurrency: 12 | group: '${{ github.workflow }} @ ${{ github.ref }}' 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | unit-test-amd64: 17 | name: Docker - Test Linux-amd64 image 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Get Runner Info 21 | run: | 22 | id 23 | pwd 24 | git --version 25 | docker version 26 | echo "TIMEOUT_SECONDS: ${{ vars.TIMEOUT_SECONDS }}" 27 | 28 | - name: Checkout 29 | uses: actions/checkout@v4 30 | 31 | - name: Set up Docker Buildx 32 | uses: docker/setup-buildx-action@v3 33 | 34 | - name: Build and export to Docker 35 | uses: docker/build-push-action@v6 36 | with: 37 | file: ./Dockerfile 38 | load: true 39 | tags: ${{ github.run_id }} 40 | platforms: linux/amd64 41 | 42 | - name: Run server 43 | run: | 44 | docker run -d \ 45 | --name sons-of-the-forest-dedicated-server \ 46 | -p 8766:8766/udp \ 47 | -p 27016:27016/udp \ 48 | -p 9700:9700/udp \ 49 | -v ./game:/sonsoftheforest/ \ 50 | --restart unless-stopped \ 51 | --stop-timeout 30 \ 52 | ${{ github.run_id }} 53 | 54 | - name: Wait for server to start 55 | run: | 56 | START_TIME=$(date +%s) 57 | echo "TIMEOUT_SECONDS: ${{ vars.TIMEOUT_SECONDS }}" 58 | 59 | # Set the timezone to Germany (Central European Time) 60 | export TZ=Europe/Berlin 61 | 62 | while ! docker logs sons-of-the-forest-dedicated-server 2>&1 | grep -q "#DSL Dedicated server loaded."; do 63 | CURRENT_TIME=$(date +%s) 64 | ELAPSED_TIME=$((CURRENT_TIME - START_TIME)) 65 | 66 | if [ $ELAPSED_TIME -gt ${{ vars.TIMEOUT_SECONDS }} ]; then 67 | echo "Timeout reached. Server failed to start within ${{ vars.TIMEOUT_SECONDS }} seconds." 68 | printf "\e[0;32m%s\e[0m\n" "*****Container LOGS*****" 69 | docker logs sons-of-the-forest-dedicated-server 70 | exit 1 71 | fi 72 | 73 | echo "$(date '+%H:%M:%S') - Waiting for server to start..." 74 | sleep 5 75 | done 76 | echo "Server successfully started" 77 | printf "\e[0;32m%s\e[0m\n" "*****Container LOGS*****" 78 | docker logs sons-of-the-forest-dedicated-server 79 | 80 | - name: Test if port 8766, 27015 and 27016 are listening 81 | run: | 82 | nc -z -u -v 127.0.0.1 8766 || exit 2 83 | nc -z -u -v 127.0.0.1 27016 || exit 3 84 | nc -z -u -v 127.0.0.1 9700 || exit 4 85 | 86 | - name: Stop server 87 | if: always() 88 | run: | 89 | docker stop sons-of-the-forest-dedicated-server 90 | docker rm sons-of-the-forest-dedicated-server 91 | docker rmi ${{ github.run_id }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | game/ 3 | steamcmd/ 4 | winedata/ 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | [Back to main](README.md#changelog) 4 | 5 | ## 2025-03-29 6 | 7 | - Added FILTER_SHADER_AND_MESH environment variable to filter out shader and mesh-related warning/error messages from the logs @jammsen (#72) 8 | 9 | ## 2025-01-26 10 | 11 | - Added Healthcheck @jammsen (#69) 12 | - Added Changelog 13 | - Updated Readme with a "table of contents", changelog and updated points from ideas of the Palworld Readme 14 | - Added Feature Request template 15 | - Updated Bug Report template 16 | - Added CI/CD unit-test, thanks to @thijsvanloef for letting me use the base 17 | 18 | [Back to main](README.md#changelog) -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM cm2network/steamcmd:root AS wine-base 2 | 3 | ENV DEBIAN_FRONTEND=noninteractive \ 4 | # Path-vars 5 | WINEPREFIX=/wine \ 6 | # Container-settings 7 | TIMEZONE=Europe/Berlin 8 | 9 | RUN ln -snf /usr/share/zoneinfo/$TIMEZONE /etc/localtime \ 10 | && echo $TIMEZONE > /etc/timezone \ 11 | && dpkg --add-architecture i386 \ 12 | && apt-get update \ 13 | && apt-get install -y --no-install-recommends --no-install-suggests software-properties-common apt-transport-https gnupg2 wget procps winbind xvfb \ 14 | && mkdir -pm755 /etc/apt/keyrings \ 15 | && wget --output-document /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key \ 16 | && wget --timestamping --directory-prefix=/etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/debian/dists/bookworm/winehq-bookworm.sources \ 17 | && apt-get update \ 18 | && apt-get install -y --no-install-recommends --no-install-suggests winehq-stable \ 19 | && apt-get remove -y --purge software-properties-common apt-transport-https gnupg2 wget \ 20 | && apt-get clean \ 21 | && apt-get autoremove -y \ 22 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 23 | 24 | FROM wine-base AS gameserver 25 | 26 | LABEL maintainer="Sebastian Schmidt - https://github.com/jammsen/docker-sons-of-the-forest-dedicated-server" 27 | LABEL org.opencontainers.image.authors="Sebastian Schmidt" 28 | LABEL org.opencontainers.image.source="https://github.com/jammsen/docker-sons-of-the-forest-dedicated-server" 29 | 30 | SHELL ["/bin/bash", "-o", "pipefail", "-c"] 31 | 32 | ENV DEBIAN_FRONTEND=noninteractive \ 33 | # Path-vars 34 | GAME_PATH="/sonsoftheforest" \ 35 | GAME_USERDATA_PATH="/sonsoftheforest/userdata" \ 36 | GAME_CONFIGFILE_PATH="/sonsoftheforest/userdata/dedicatedserver.cfg" \ 37 | STEAMCMD_PATH="/home/steam/steamcmd" \ 38 | WINEDATA_PATH="/winedata" \ 39 | # Wine/Xvfb-settings 40 | WINEARCH=win64 \ 41 | WINEPREFIX="/winedata/WINE64" \ 42 | DISPLAY=:1.0 \ 43 | # Container-settings 44 | TIMEZONE=Europe/Berlin \ 45 | PUID=1000 \ 46 | PGID=1000 \ 47 | FILTER_SHADER_AND_MESH=true \ 48 | # SteamCMD-settings 49 | ALWAYS_UPDATE_ON_START=true \ 50 | # Gameserver-start-settings-overrides 51 | SKIP_NETWORK_ACCESSIBILITY_TEST=true 52 | 53 | 54 | VOLUME ["${GAME_PATH}"] 55 | 56 | EXPOSE 8766/udp 27016/udp 9700/udp 57 | 58 | COPY --chmod=755 entrypoint.sh / 59 | COPY --chmod=755 scripts/ /scripts 60 | COPY --chmod=755 includes/ /includes 61 | COPY --chmod=644 configs/steam_appid.txt / 62 | COPY --chmod=644 configs/ownerswhitelist.txt.example / 63 | COPY --chmod=644 configs/dedicatedserver.cfg.example / 64 | COPY --chmod=755 gosu-amd64 /usr/local/bin/gosu 65 | 66 | RUN ln -snf /usr/share/zoneinfo/$TIMEZONE /etc/localtime \ 67 | && echo $TIMEZONE > /etc/timezone \ 68 | && mkdir -p ${WINEPREFIX} 69 | 70 | HEALTHCHECK --interval=10s --timeout=10s --start-period=30s --retries=3 \ 71 | CMD pgrep -x "SonsOfTheForest" >/dev/null 2>&1 || exit 1 72 | 73 | ENTRYPOINT ["/entrypoint.sh"] 74 | CMD ["/scripts/servermanager.sh"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker - Sons of the Forest Dedicated Server 2 | 3 | [![Build-Status master](https://github.com/jammsen/docker-sons-of-the-forest-dedicated-server/blob/master/.github/workflows/docker-build-and-push-prod.yml/badge.svg)](https://github.com/jammsen/docker-sons-of-the-forest-dedicated-server/blob/master/.github/workflows/docker-build-and-push-prod.yml) 4 | ![Docker Pulls](https://img.shields.io/docker/pulls/jammsen/sons-of-the-forest-dedicated-server) 5 | ![Docker Stars](https://img.shields.io/docker/stars/jammsen/sons-of-the-forest-dedicated-server) 6 | ![Image Size](https://img.shields.io/docker/image-size/jammsen/sons-of-the-forest-dedicated-server/latest) 7 | [![Discord](https://img.shields.io/discord/532141442731212810?logo=discord&label=Discord&link=https%3A%2F%2Fdiscord.gg%2F7tacb9Q6tj)](https://discord.gg/7tacb9Q6tj) 8 | 9 | > [!TIP] 10 | > Do you want to chat with the community? 11 | > 12 | > **[Join us on Discord](https://discord.gg/7tacb9Q6tj)** 13 | 14 | > [!WARNING] 15 | > Update Jan-2025: This Docker-Image had a major refactoring including breaking changes in downwards-compability. This was done for removing dependency of "root" in the image, which caused various SteamCMD, NAS, QNAP, Synology and Portainer problems. Also the Docker-Base-Image was switched and there was better process-handling added to make sure the process exits cleanly, no matter how Docker or the User stops the server. 16 | > 17 | > It is recommended to do a fresh install, via the new readme in a fresh directory to understand what changed and work backwards to adapt the changes, or migrate the savegame from the old server to the new one, up to you. If you need help, feel free to join the Discord server and ask in the right channel for the game. 18 | 19 | > [!NOTE] 20 | > If you are looking for the TheForest version, please look here: https://github.com/jammsen/docker-the-forest-dedicated-server 21 | 22 | This repository includes a Sons of the Forest Dedicated Server based on Docker with Wine and an example config. 23 | 24 | ___ 25 | 26 | ## Table of Contents 27 | 28 | - [Docker - Sons of the Forest Dedicated Server](#docker---sons-of-the-forest-dedicated-server) 29 | - [Table of Contents](#table-of-contents) 30 | - [How to ask for support for this Docker image](#how-to-ask-for-support-for-this-docker-image) 31 | - [Requirements](#requirements) 32 | - [Minimum system requirements](#minimum-system-requirements) 33 | - [Changelog](#changelog) 34 | - [Wiki](#wiki) 35 | - [Getting started](#getting-started) 36 | - [Docker-Compose - Example](#docker-compose---example) 37 | - [Planned features in the future](#planned-features-in-the-future) 38 | - [Software used](#software-used) 39 | 40 | 41 | ## How to ask for support for this Docker image 42 | 43 | If you need support for this Docker image: 44 | 45 | - Feel free to create a new issue. 46 | - You can reference other issues if you're experiencing a similar problem via #issue-number. 47 | - Follow the instructions and answer the questions of people who are willing to help you. 48 | - Once your issue is resolved, please close it and please consider giving this repo and the [Docker-Hub repository](https://hub.docker.com/repository/docker/jammsen/sons-of-the-forest-dedicated-server) a star. 49 | - Please note that any issue that has been inactive for a week will be closed due to inactivity. 50 | 51 | Please avoid: 52 | 53 | - Reusing or necroing issues. This can lead to spam and may harass participants who didn't agree to be part of your new problem. 54 | - If this happens, we reserve the right to lock the issue or delete the comments, you have been warned! 55 | 56 | ## Requirements 57 | 58 | To run this Docker image, you need a basic understanding of Docker, Docker-Compose, Linux, and Networking (Port-Forwarding/NAT). 59 | 60 | ## Minimum system requirements 61 | 62 | | Resource | Minimum (2-4 Players) | Recommended (4 Players) | 63 | | -------- | ----------------------- | ----------------------- | 64 | | CPU | 2-4 CPU-Cores @ Mid GHz | 4+ CPU Cores @ High GHz | 65 | | RAM | 8GB+ RAM | 16GB+ RAM | 66 | | Storage | 12GB+ | 20GB+ (SSD prefered) | 67 | 68 | ## Changelog 69 | 70 | You can find the [changelog here](CHANGELOG.md) 71 | 72 | ## Wiki 73 | 74 | > [!TIP] 75 | > Currently out-dated, because of Major refactoring, with breaking changes! 76 | 77 | ~~We have very detailed instruction in our [Wiki](https://github.com/jammsen/docker-sons-of-the-forest-dedicated-server/wiki) page.~~ 78 | 79 | ## Getting started 80 | 81 | If you already hosted some containers, just follow these steps: 82 | 83 | 1. Go to the directory you want to host your gameserver on your Dockernode 84 | 2. Create a sub-directory called `game` 85 | 3. Download the [docker-compose.yml](docker-compose.yml) or use the following example 86 | 4. Review the file and setup the settings you like 87 | 5. Setup Port-Forwarding or NAT for the ports in the Docker-Compose file 88 | 6. Start the container via Docker Compose 89 | 7. (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/userdata/dedicatedserver.cfg`) 90 | 91 | ### Docker-Compose - Example 92 | 93 | ```yaml 94 | version: '3.9' 95 | services: 96 | sons-of-the-forest-dedicated-server: 97 | container_name: sons-of-the-forest-dedicated-server 98 | image: jammsen/sons-of-the-forest-dedicated-server:latest 99 | restart: always 100 | environment: 101 | PUID: 1000 102 | PGID: 1000 103 | ALWAYS_UPDATE_ON_START: true 104 | SKIP_NETWORK_ACCESSIBILITY_TEST: true 105 | FILTER_SHADER_AND_MESH: true 106 | ports: 107 | - 8766:8766/udp 108 | - 27016:27016/udp 109 | - 9700:9700/udp 110 | volumes: 111 | - ./game:/sonsoftheforest 112 | ``` 113 | 114 | > **Note:** The `FILTER_SHADER_AND_MESH` environment variable (default: true) controls whether shader-related warning messages are filtered from the container logs. When set to true, it removes the following messages keeping your logs cleaner. Set to false if you want to see all shader warnings. 115 | > * Shader XYZ shader is not supported on this GPU 116 | > * WARNING: Shader Unsupported: 'XYZ' - All subshaders removed 117 | > * WARNING: Shader Did you use XYZ and omit this platform? 118 | > * WARNING: Shader If subshaders removal was intentional, you may have forgotten turning Fallback off? 119 | > * No mesh data available for mesh XYZ 120 | > * Couldn't create a Convex Mesh from source mesh XYZ 121 | 122 | ## Planned features in the future 123 | 124 | - Feel free to suggest features in the issues 125 | 126 | ## Software used 127 | 128 | - Debian Stable and SteamCMD via cm2network/steamcmd:root image as base-image 129 | - gosu 130 | - procps 131 | - winbind 132 | - wine 133 | - xvfb 134 | - SonsOfTheForest Dedicated Server (APP-ID: 2465200) 135 | -------------------------------------------------------------------------------- /configs/dedicatedserver.cfg.example: -------------------------------------------------------------------------------- 1 | { 2 | "IpAddress": "0.0.0.0", 3 | "GamePort": 8766, 4 | "QueryPort": 27016, 5 | "BlobSyncPort": 9700, 6 | "ServerName": "jammsen-docker-generated-###RANDOM###", 7 | "MaxPlayers": 8, 8 | "Password": "", 9 | "LanOnly": false, 10 | "SaveSlot": 1, 11 | "SaveMode": "Continue", 12 | "GameMode": "Normal", 13 | "SaveInterval": 600, 14 | "IdleDayCycleSpeed": 0.0, 15 | "IdleTargetFramerate": 5, 16 | "ActiveTargetFramerate": 60, 17 | "LogFilesEnabled": false, 18 | "TimestampLogFilenames": true, 19 | "TimestampLogEntries": true, 20 | "SkipNetworkAccessibilityTest": false, 21 | "GameSettings": {}, 22 | "CustomGameModeSettings": {} 23 | } -------------------------------------------------------------------------------- /configs/ownerswhitelist.txt.example: -------------------------------------------------------------------------------- 1 | # In order to be able to administrate your server from in game directly, you will need to setup server ownership. 2 | # Add below the steam ids of every server owner, one steam id per line. 3 | # To find your SteamID, open Steam and click on your name on the top right, then go to Account Details. 4 | # You can use # to comment out a line. That can be helpful to keep track of SteamIDs, you can include their name in the line above or below, starting with a #. 5 | 6 | 7 | -------------------------------------------------------------------------------- /configs/steam_appid.txt: -------------------------------------------------------------------------------- 1 | 1326470 -------------------------------------------------------------------------------- /docker-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | docker build "$@" --tag=jammsen/sons-of-the-forest-dedicated-server:latest . 3 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | services: 3 | sons-of-the-forest-dedicated-server: 4 | container_name: sons-of-the-forest-dedicated-server 5 | image: jammsen/sons-of-the-forest-dedicated-server:latest 6 | restart: always 7 | environment: 8 | PUID: 1000 9 | PGID: 1000 10 | ALWAYS_UPDATE_ON_START: true 11 | SKIP_NETWORK_ACCESSIBILITY_TEST: true 12 | ports: 13 | - 8766:8766/udp 14 | - 27016:27016/udp 15 | - 9700:9700/udp 16 | volumes: 17 | - ./game:/sonsoftheforest 18 | -------------------------------------------------------------------------------- /docker-exec.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | docker exec -u steam:steam -it sons-of-the-forest-dedicated-server bash -------------------------------------------------------------------------------- /docker-run-bash.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | docker run --rm -i -t -p 8766:8766/udp -p 27016:27016/udp -p 9700:9700/udp -v "$(pwd)"/game:/sonsoftheforest --name sons-of-the-forest-dedicated-server jammsen/sons-of-the-forest-dedicated-server:latest bash 3 | -------------------------------------------------------------------------------- /docker-run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | docker run --rm -i -t -p 8766:8766/udp -p 27016:27016/udp -p 9700:9700/udp -v "$(pwd)"/game:/sonsoftheforest --name sons-of-the-forest-dedicated-server jammsen/sons-of-the-forest-dedicated-server:latest 3 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # shellcheck disable=SC1091 3 | # https://stackoverflow.com/questions/27669950/difference-between-euid-and-uid 4 | 5 | set -e 6 | 7 | APP_USER=steam 8 | APP_GROUP=steam 9 | APP_HOME=/home/$APP_USER 10 | 11 | source /includes/colors.sh 12 | 13 | if [[ "${EUID}" -ne 0 ]]; then 14 | ee ">>> This Docker-Container must be run as root! Please adjust how you started the container, to fix this error." 15 | exit 1 16 | fi 17 | 18 | if [[ "${PUID}" -eq 0 ]] || [[ "${PGID}" -eq 0 ]]; then 19 | ee ">>> Running SOTF as root is not supported, please fix your PUID and PGID!" 20 | exit 1 21 | elif [[ "$(id -u steam)" -ne "${PUID}" ]] || [[ "$(id -g steam)" -ne "${PGID}" ]]; then 22 | ew "> Current $APP_USER user PUID is '$(id -u steam)' and PGID is '$(id -g steam)'" 23 | ew "> Setting new $APP_USER user PUID to '${PUID}' and PGID to '${PGID}'" 24 | groupmod -g "${PGID}" "$APP_GROUP" && usermod -u "${PUID}" -g "${PGID}" "$APP_USER" 25 | else 26 | ew "> Current $APP_USER user PUID is '$(id -u steam)' and PGID is '$(id -g steam)'" 27 | ew "> PUID and PGID matching what is requested for user $APP_USER" 28 | fi 29 | 30 | chown -R "$APP_USER":"$APP_GROUP" "$APP_HOME" 31 | chown -R "$APP_USER":"$APP_GROUP" "$GAME_PATH" 32 | chown -R "$APP_USER":"$APP_GROUP" "$WINEDATA_PATH" 33 | 34 | ew_nn "> id steam: " ; e "$(id steam)" 35 | 36 | exec gosu $APP_USER:$APP_GROUP "$@" -------------------------------------------------------------------------------- /gosu-amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jammsen/docker-sons-of-the-forest-dedicated-server/124c214f3206d8456f05c75deb237b8e07cdc8df/gosu-amd64 -------------------------------------------------------------------------------- /includes/colors.sh: -------------------------------------------------------------------------------- 1 | # shellcheck disable=SC2148 2 | # Idea from https://colors.sh/ 3 | # ANSI Color Codes - https://www.shellhacks.com/bash-colors/ 4 | # Ansi Default Color Codes https://hyperskill.org/learn/step/18193#terminal-support 5 | # Use ANSI whenever possible. Makes logs compatible with almost all systems. 6 | 7 | # Aliases for colorful echos with newlines 8 | function e() { 9 | colorful_echos --base "${@}" 10 | echo "" 11 | } 12 | 13 | function ee() { 14 | colorful_echos --error "${@}" 15 | echo "" 16 | } 17 | 18 | function ei() { 19 | colorful_echos --info "${@}" 20 | echo "" 21 | } 22 | 23 | function es() { 24 | colorful_echos --success "${@}" 25 | echo "" 26 | } 27 | 28 | function ew() { 29 | colorful_echos --warning "${@}" 30 | echo "" 31 | } 32 | 33 | # Aliases for colorful echos without newlines 34 | function e_nn() { 35 | colorful_echos --base "${@}" 36 | } 37 | 38 | function ee_nn() { 39 | colorful_echos --error "${@}" 40 | } 41 | 42 | function ei_nn() { 43 | colorful_echos --info "${@}" 44 | } 45 | 46 | function es_nn() { 47 | colorful_echos --success "${@}" 48 | } 49 | 50 | function ew_nn() { 51 | colorful_echos --warning "${@}" 52 | } 53 | 54 | # This creates a wrapper for echo to add colors 55 | function colorful_echos() { 56 | # Set color constants 57 | BASE="\e[97m" # Clean color 58 | CLEAN="\e[0m" # Clean color 59 | ERROR="\e[91m" # Red color for error 60 | INFO="\e[94m" # Blue color for info 61 | SUCCESS="\e[92m" # Green color for success 62 | WARNING="\e[93m" # Yellow color for warning 63 | 64 | if [ $# -gt 2 ]; then 65 | echo "Usage: $0 [--success|--error|--info|--warning|--base] " 66 | exit 1 67 | fi 68 | 69 | # Parse arguments 70 | arg1=$1 71 | message=$2 72 | 73 | # Set color based on argument 74 | if [ "$arg1" == "--success" ]; then 75 | color="$SUCCESS" 76 | elif [ "$arg1" == "--error" ]; then 77 | color="$ERROR" 78 | elif [ "$arg1" == "--info" ]; then 79 | color="$INFO" 80 | elif [ "$arg1" == "--warning" ]; then 81 | color="$WARNING" 82 | elif [ "$arg1" == "--base" ]; then 83 | color="$BASE" 84 | else 85 | echo -ne "$message" 86 | return 0 87 | fi 88 | 89 | # print newlines in the beggining of the message 90 | while [ "${message:0:2}" = "\\n" ]; do 91 | # Print a newline 92 | echo "" 93 | # Remove the first two characters from the message 94 | message="${message:2}" 95 | done 96 | 97 | # Print message with the specified color 98 | echo -ne "${color}${message}${CLEAN}" 99 | } -------------------------------------------------------------------------------- /scripts/servermanager.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # shellcheck disable=SC1091 3 | # IF Bash extension used: 4 | # https://stackoverflow.com/a/13864829 5 | # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02 6 | 7 | # Uncomment for debugging 8 | #set -x 9 | 10 | source /includes/colors.sh 11 | 12 | function isServerRunning() { 13 | if ps axg | grep -F "SonsOfTheForestDS.exe" | grep -v -F 'grep' > /dev/null; then 14 | true 15 | else 16 | false 17 | fi 18 | } 19 | 20 | function isVirtualScreenRunning() { 21 | if ps axg | grep -F "Xvfb :1 -screen 0 1024x768x24" | grep -v -F 'grep' > /dev/null; then 22 | true 23 | else 24 | false 25 | fi 26 | } 27 | 28 | function isWineinBashRcExistent() { 29 | grep "wine" /etc/bash.bashrc > /dev/null 30 | if [[ $? -ne 0 ]]; then 31 | ei ">>> Checking if Wine is set in bashrc" 32 | setupWineInBashRc 33 | fi 34 | } 35 | 36 | function setupWineInBashRc() { 37 | ei ">>> Setting up Wine in bashrc" 38 | mkdir -p "$WINEPREFIX" 39 | if [ ! -d "$WINEPREFIX"/drive_c/windows ]; then 40 | # shellcheck disable=SC2164 41 | cd "$WINEDATA_PATH" 42 | ei ">>> Setting up WineConfig and waiting 15 seconds" 43 | winecfg > /dev/null 2>&1 44 | sleep 15 45 | fi 46 | } 47 | 48 | function startVirtualScreenAndRebootWine() { 49 | # Start X Window Virtual Framebuffer 50 | Xvfb :1 -screen 0 1024x768x24 & 51 | wineboot -r 52 | } 53 | 54 | function installServer() { 55 | RANDOM_NUMBER=$RANDOM 56 | # force a fresh install of all 57 | ei ">>> Doing a fresh install of the gameserver" 58 | ei "> Setting server-name to jammsen-docker-generated-$RANDOM_NUMBER" 59 | 60 | isWineinBashRcExistent 61 | mkdir -p "$GAME_USERDATA_PATH" 62 | 63 | # only copy steam_appid.txt if doesn't exist 64 | if [ ! -f "$GAME_PATH" ]; then 65 | cp /steam_appid.txt "$GAME_PATH"/steam_appid.txt 66 | fi 67 | 68 | # only copy dedicatedserver.cfg if doesn't exist 69 | if [ ! -f "$GAME_CONFIGFILE_PATH" ]; then 70 | cp /dedicatedserver.cfg.example "$GAME_CONFIGFILE_PATH" 71 | sed -i -e "s/###RANDOM###/$RANDOM_NUMBER/g" "$GAME_CONFIGFILE_PATH" 72 | fi 73 | 74 | # only copy ownerswhitelist.txt if doesn't exist 75 | if [ ! -f "$GAME_USERDATA_PATH/ownerswhitelist.txt" ]; then 76 | cp /ownerswhitelist.txt.example "$GAME_USERDATA_PATH/ownerswhitelist.txt" 77 | fi 78 | 79 | "${STEAMCMD_PATH}"/steamcmd.sh +@sSteamCmdForcePlatformType windows +force_install_dir "$GAME_PATH" +login anonymous +app_update 2465200 validate +quit 80 | } 81 | 82 | function updateServer() { 83 | # force an update and validation 84 | ei ">>> Doing an update of the gameserver" 85 | "${STEAMCMD_PATH}"/steamcmd.sh +@sSteamCmdForcePlatformType windows +force_install_dir "$GAME_PATH" +login anonymous +app_update 2465200 validate +quit 86 | } 87 | 88 | function startServer() { 89 | isWineinBashRcExistent 90 | if ! isVirtualScreenRunning; then 91 | startVirtualScreenAndRebootWine 92 | fi 93 | ei ">>> Starting the gameserver" 94 | rm -f /tmp/.X1-lock 2> /dev/null 95 | # shellcheck disable=SC2164 96 | cd "$GAME_PATH" 97 | 98 | if [[ ${FILTER_SHADER_AND_MESH} == true ]]; then 99 | ei ">>> Shader and Mesh warning/error filtering is enabled" 100 | # Start the server and pipe through grep to filter out shader warnings 101 | wine64 "$GAME_PATH"/SonsOfTheForestDS.exe -userdatapath "$GAME_USERDATA_PATH" 2>&1 | grep -v -E ".*WARNING: Shader.*|.*ERROR: Shader.*|.*No mesh data available for mesh.*|.*Couldn't create a Convex Mesh from source.*|.*The referenced script.*|.*Could not find video decode shader pass.*" 102 | else 103 | ei ">>> Shader warning filtering is disabled" 104 | # Start the server normally without filtering 105 | wine64 "$GAME_PATH"/SonsOfTheForestDS.exe -userdatapath "$GAME_USERDATA_PATH" 106 | fi 107 | } 108 | 109 | function stopServer() { 110 | ew ">>> Stopping server..." 111 | kill -SIGTERM "$(pidof SonsOfTheForestDS.exe)" 112 | tail --pid="$(pidof SonsOfTheForestDS.exe)" -f 2>/dev/null 113 | ew ">>> Server stopped gracefully" 114 | exit 143; 115 | } 116 | 117 | # Handler for SIGTERM from docker-based stop events 118 | function term_handler() { 119 | stopServer 120 | } 121 | 122 | function startMain() { 123 | # Check if server is installed, if not try again 124 | if [[ ! -f "/sonsoftheforest/SonsOfTheForestDS.exe" ]]; then 125 | installServer 126 | fi 127 | if [[ ${ALWAYS_UPDATE_ON_START} == true ]]; then 128 | updateServer 129 | fi 130 | if [[ -n ${SKIP_NETWORK_ACCESSIBILITY_TEST+x} ]]; then 131 | ei ">>> Setting SkipNetworkAccessibilityTest to '$SKIP_NETWORK_ACCESSIBILITY_TEST'" 132 | # shellcheck disable=SC2086 133 | sed -E -i 's/"SkipNetworkAccessibilityTest":\s*(false|true)/"SkipNetworkAccessibilityTest": '$SKIP_NETWORK_ACCESSIBILITY_TEST'/' "$GAME_CONFIGFILE_PATH" 134 | fi 135 | startServer 136 | } 137 | 138 | 139 | # Bash-Trap for exit signals to handle 140 | trap 'kill ${!}; term_handler' SIGTERM 141 | 142 | # Main process loop 143 | while true 144 | do 145 | current_date=$(date +%Y-%m-%d) 146 | current_time=$(date +%H:%M:%S) 147 | ei ">>> Starting server manager" 148 | e "> Started at: $current_date $current_time" 149 | ei ">>> Listing config options ..." 150 | e "> ALWAYS_UPDATE_ON_START is set to: $ALWAYS_UPDATE_ON_START" 151 | e "> SKIP_NETWORK_ACCESSIBILITY_TEST is set to: $SKIP_NETWORK_ACCESSIBILITY_TEST" 152 | e "> FILTER_SHADER_AND_MESH is set to: $FILTER_SHADER_AND_MESH" 153 | 154 | startMain & 155 | START_MAIN_PID="$!" 156 | 157 | ew ">>> Server main thread started with pid ${START_MAIN_PID}" 158 | wait ${START_MAIN_PID} 159 | exit 0; 160 | done --------------------------------------------------------------------------------