├── .github ├── readme │ ├── logo.png │ └── logo.psd └── workflows │ ├── pipeline.yml │ ├── scheduled-security-audit.yaml │ └── test-image.sh ├── .gitignore ├── README.md ├── container-data ├── Containerfile └── pre.sh ├── docker-compose.yml └── renovate.json /.github/readme/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RouHim/sons-of-the-forest-container-image/2702286c6563934a5915c8196b3b1f99f578a879/.github/readme/logo.png -------------------------------------------------------------------------------- /.github/readme/logo.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RouHim/sons-of-the-forest-container-image/2702286c6563934a5915c8196b3b1f99f578a879/.github/readme/logo.psd -------------------------------------------------------------------------------- /.github/workflows/pipeline.yml: -------------------------------------------------------------------------------- 1 | name: Container release pipeline 2 | 3 | 4 | on: 5 | push: 6 | workflow_dispatch: # Allows you to run this workflow manually from the Actions tab 7 | pull_request: 8 | types: 9 | - opened 10 | schedule: 11 | - cron: "0 0 * * 0" # weekly at sunday night 12 | 13 | 14 | # Avoid running this workflow multiple times at the same branch 15 | concurrency: 16 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 17 | cancel-in-progress: true 18 | 19 | 20 | env: 21 | IMAGE_NAME: rouhim/sons-of-the-forest-server 22 | IMAGE_TAG: latest 23 | 24 | 25 | jobs: 26 | 27 | 28 | check-containerfile: 29 | name: Check container file 30 | runs-on: ubuntu-latest 31 | steps: 32 | - name: Checkout code 33 | uses: actions/checkout@v4 34 | 35 | - name: Run Trivy vulnerability scanner 36 | uses: aquasecurity/trivy-action@master 37 | with: 38 | scan-type: 'config' 39 | hide-progress: false 40 | format: 'table' 41 | exit-code: '1' 42 | ignore-unfixed: true 43 | severity: 'CRITICAL,HIGH' 44 | 45 | 46 | build-test-push-image: 47 | needs: check-containerfile 48 | runs-on: ubuntu-latest 49 | steps: 50 | - name: Checkout 51 | uses: actions/checkout@v4 52 | 53 | - name: Set up Docker Buildx 54 | uses: docker/setup-buildx-action@v3 55 | 56 | - name: Login to Docker Hub 57 | uses: docker/login-action@v3 58 | with: 59 | username: ${{ secrets.DOCKERHUB_USERNAME }} 60 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 61 | 62 | - name: Build container image 63 | uses: docker/build-push-action@v6 64 | with: 65 | tags: ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} 66 | platforms: linux/amd64 67 | context: container-data 68 | file: container-data/Containerfile 69 | load: true 70 | push: false 71 | 72 | - name: Run Trivy vulnerability scanner 73 | uses: aquasecurity/trivy-action@master 74 | with: 75 | scan-type: image 76 | image-ref: ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} 77 | format: 'table' 78 | exit-code: '1' 79 | ignore-unfixed: true 80 | severity: 'CRITICAL,HIGH' 81 | 82 | - name: Test the built image 83 | run: | 84 | mkdir -p config/ data/ 85 | chmod 777 config/ data/ 86 | timeout 10m bash .github/workflows/test-image.sh 87 | 88 | - name: Build and push container image 89 | if: github.ref == 'refs/heads/main' 90 | uses: docker/build-push-action@v6 91 | with: 92 | tags: ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} 93 | platforms: linux/amd64 94 | context: container-data 95 | file: container-data/Containerfile 96 | load: false 97 | push: true 98 | 99 | - name: Update docker hub description 100 | if: github.ref == 'refs/heads/main' 101 | uses: peter-evans/dockerhub-description@v4 102 | with: 103 | username: ${{ secrets.DOCKERHUB_USERNAME }} 104 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 105 | repository: ${{ env.IMAGE_NAME }} 106 | 107 | - name: Run Trivy vulnerability scanner 108 | uses: aquasecurity/trivy-action@master 109 | with: 110 | scan-type: image 111 | image-ref: ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} 112 | exit-code: '0' 113 | ignore-unfixed: true 114 | severity: 'CRITICAL,HIGH' 115 | format: 'sarif' 116 | output: 'trivy-results.sarif' 117 | - name: Upload Trivy scan results to GitHub Security tab 118 | uses: github/codeql-action/upload-sarif@v3 119 | with: 120 | sarif_file: 'trivy-results.sarif' -------------------------------------------------------------------------------- /.github/workflows/scheduled-security-audit.yaml: -------------------------------------------------------------------------------- 1 | name: Security Audits 2 | on: 3 | schedule: 4 | - cron: '0 0 * * *' # every day at midnight 5 | workflow_dispatch: # allow manual execution 6 | 7 | env: 8 | IMAGE_NAME: rouhim/sons-of-the-forest-server 9 | IMAGE_TAG: latest 10 | 11 | jobs: 12 | image-audit: 13 | name: Audit container image 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v4 18 | 19 | - name: Print to console 20 | uses: aquasecurity/trivy-action@master 21 | with: 22 | image-ref: 'docker.io/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}' 23 | format: 'table' 24 | exit-code: '0' 25 | 26 | - name: Save to github security tab 27 | uses: aquasecurity/trivy-action@master 28 | with: 29 | image-ref: 'docker.io/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}' 30 | format: 'sarif' 31 | output: 'trivy-results.sarif' 32 | exit-code: '0' 33 | ignore-unfixed: true 34 | severity: 'CRITICAL,HIGH' 35 | - name: Upload Trivy scan results to GitHub Security tab 36 | uses: github/codeql-action/upload-sarif@v3 37 | with: 38 | sarif_file: 'trivy-results.sarif' 39 | 40 | - name: Fail if vulnerabilities found 41 | uses: aquasecurity/trivy-action@master 42 | with: 43 | image-ref: 'docker.io/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}' 44 | format: 'table' 45 | exit-code: '1' 46 | ignore-unfixed: true 47 | severity: 'CRITICAL,HIGH' 48 | 49 | filesystem-audit: 50 | name: Audit repo filesystem 51 | runs-on: ubuntu-latest 52 | steps: 53 | - name: Checkout code 54 | uses: actions/checkout@v4 55 | 56 | - name: Print to console 57 | uses: aquasecurity/trivy-action@master 58 | with: 59 | scan-type: 'fs' 60 | format: 'table' 61 | exit-code: '0' 62 | 63 | - name: Save to github security tab 64 | uses: aquasecurity/trivy-action@master 65 | with: 66 | scan-type: 'fs' 67 | format: 'sarif' 68 | output: 'trivy-results.sarif' 69 | exit-code: '0' 70 | ignore-unfixed: true 71 | severity: 'CRITICAL,HIGH' 72 | - name: Upload Trivy scan results to GitHub Security tab 73 | uses: github/codeql-action/upload-sarif@v3 74 | with: 75 | sarif_file: 'trivy-results.sarif' 76 | 77 | - name: Fail if vulnerabilities found 78 | uses: aquasecurity/trivy-action@master 79 | with: 80 | scan-type: 'fs' 81 | format: 'table' 82 | exit-code: '1' 83 | ignore-unfixed: true 84 | severity: 'CRITICAL,HIGH' 85 | 86 | config-audit: 87 | name: Audit config files 88 | runs-on: ubuntu-latest 89 | steps: 90 | - name: Checkout code 91 | uses: actions/checkout@v4 92 | 93 | - name: Print to console 94 | uses: aquasecurity/trivy-action@master 95 | with: 96 | scan-type: 'config' 97 | hide-progress: false 98 | format: 'table' 99 | exit-code: '0' 100 | 101 | - name: Save to github security tab 102 | uses: aquasecurity/trivy-action@master 103 | with: 104 | scan-type: 'config' 105 | hide-progress: false 106 | format: 'sarif' 107 | output: 'trivy-results.sarif' 108 | exit-code: '0' 109 | ignore-unfixed: true 110 | severity: 'CRITICAL,HIGH' 111 | - name: Upload Trivy scan results to GitHub Security tab 112 | uses: github/codeql-action/upload-sarif@v3 113 | with: 114 | sarif_file: 'trivy-results.sarif' 115 | 116 | - name: Fail if misconfiguration found 117 | uses: aquasecurity/trivy-action@master 118 | with: 119 | scan-type: 'config' 120 | hide-progress: false 121 | format: 'table' 122 | exit-code: '1' 123 | ignore-unfixed: true 124 | severity: 'CRITICAL,HIGH' -------------------------------------------------------------------------------- /.github/workflows/test-image.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Spin up a new container 4 | echo "🚀 Spinning up a test container" 5 | docker compose up -d 6 | 7 | # Loop until the string is found 8 | echo "🔍 Checking for the desired string in the logs..." 9 | while true; do 10 | # Check if the desired string is in the logs 11 | if docker compose logs | grep -q "Please restart the server"; then 12 | echo "✅ Dedicated server started successfully" 13 | break 14 | fi 15 | 16 | # Print the 5 lines tail of the logs 17 | echo "📃 Desired string not found in the logs, printing the last 5 lines of the logs:" 18 | echo "========================================" 19 | docker compose logs --tail 5 20 | echo "========================================" 21 | 22 | # Wait for 5 seconds before checking again 23 | echo "⏳ Waiting for 5 seconds before checking again..." 24 | sleep 5 25 | done 26 | 27 | # Cleanup and exit with 0 28 | docker compose kill && docker compose down --volumes 29 | echo "✅ Done, everything looks good" 30 | exit 0 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | data/ 3 | config/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 | This repository provides a safe container image for the Sons of the Forest game server. 17 | It is designed to be used with Docker Compose, making it easy to set up and manage your game server environment. 18 |
19 | 20 | ## Requirements 21 | 22 | * [Docker](https://docs.docker.com/engine/install/) 23 | * [Docker Compose](https://docs.docker.com/compose/install/standalone/) 24 | * At least 8GB RAM 25 | 26 | ## Installation 27 | 28 | Once _Docker_ and _Docker Compose_ are installed, clone this repository to your local machine: 29 | 30 | ```bash 31 | git clone https://github.com/RouHim/sons-of-the-forest-container-image.git 32 | cd sons-of-the-forest-container-image 33 | ``` 34 | 35 | Before starting the server, create the required folder structure, and adjust the permissions: 36 | 37 | ```bash 38 | mkdir config/ data/ 39 | chmod 777 config/ data/ 40 | ``` 41 | 42 | > The `chmod` command is recommended to avoid permission issues. 43 | > The main reason is, that the user in the container, most likely differs from the user on the host. 44 | 45 | ## Usage 46 | 47 | To start the Sons of the Forest server, navigate to the cloned repository's directory and use Docker Compose: 48 | 49 | ```bash 50 | docker compose pull 51 | docker compose up -d 52 | ``` 53 | 54 | This will pull the latest image and start the server in detached mode. 55 | 56 | When starting the server for the first time: 57 | 58 | * The config files and folders will be automatically created in the `config/` folder. 59 | * The server will download the latest version of the game from Steam to the `data/` folder. 60 | 61 | > You have to restart after the first start. 62 | 63 | To restart the server after making changes to the configuration, use the following command: 64 | 65 | ```bash 66 | docker compose restart 67 | ``` 68 | 69 | To check the server logs, use the following command: 70 | 71 | ```bash 72 | docker compose logs -f 73 | ``` 74 | 75 | ## Update 76 | 77 | To update the server, just restart the container. 78 | The server checks for updates and validates on every boot per default. 79 | 80 | > To skip update and validation of the server files on every boot, 81 | > set the `FAST_BOOT` env variable to `true`. 82 | 83 | ## Configuration 84 | 85 | > The server configuration does not differ from the official server configuration. 86 | > Just follow an existing server configuration guide 87 | > like [this](https://steamcommunity.com/sharedfiles/filedetails/?id=2992700419&snr=1_2108_9__2107). 88 | 89 | The `config` folder contains the configuration files for the game server: 90 | 91 | * The server owners list, in a file called `ownerswhitelist.txt` 92 | * The game server configuration, in a file called `dedicatedserver.cfg` 93 | * The game saves, in a folder called `Saves` 94 | * The game settings, in a file called `SonsGameSettings.cfg` 95 | 96 | All files and folders in the `config` will be created automatically when the server is started for the first time. 97 | 98 | > `SkipNetworkAccessibilityTest` is always forced to `true`, 99 | > because the test method is not working in a container environment. 100 | 101 | 102 | The `data/` folder contains the game server data. 103 | Feel free to modify files in this folder, 104 | but be aware that the game server must be restarted for changes to take effect. 105 | The folder can be deleted to reset the game server to its default state. 106 | 107 | # Resources 108 | 109 | - Inspired by: https://github.com/jammsen/docker-sons-of-the-forest-dedicated-server 110 | - Built from: https://github.com/RouHim/sons-of-the-forest-container-image 111 | - Built to: https://hub.docker.com/r/rouhim/sons-of-the-forest-server 112 | - Based on: https://github.com/RouHim/steamcmd-wine-container-image 113 | - SteamCMD Documentation: https://developer.valvesoftware.com/wiki/SteamCMD 114 | - Dedicated server guide: https://steamcommunity.com/sharedfiles/filedetails/?id=2992700419&snr=1_2108_9__2107 115 | -------------------------------------------------------------------------------- /container-data/Containerfile: -------------------------------------------------------------------------------- 1 | FROM rouhim/steamcmd-wine:latest 2 | USER $USER 3 | 4 | ENV STEAM_APP_ID "2465200" 5 | ENV STARTUP_COMMAND "wine SonsOfTheForestDS.exe -userdatapath $SERVER_CONFIG_DIR" 6 | 7 | # Game port 8 | EXPOSE 8766/udp 9 | # Query port 10 | EXPOSE 27016/udp 11 | # Blobsync port 12 | EXPOSE 9700/udp 13 | 14 | COPY pre.sh $USER_HOME/pre.sh -------------------------------------------------------------------------------- /container-data/pre.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | 4 | # Set skip network accessibility test to true 5 | echo "🔧 Adjust server config..." 6 | sed -i 's/"SkipNetworkAccessibilityTest": false/"SkipNetworkAccessibilityTest": true/g' "$SERVER_CONFIG_DIR"/dedicatedserver.cfg 7 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | sons-of-the-forest-server: 3 | image: rouhim/sons-of-the-forest-server 4 | build: 5 | context: container-data 6 | dockerfile: Containerfile 7 | restart: unless-stopped 8 | environment: 9 | FAST_BOOT: "false" 10 | volumes: 11 | - "./config:/config" 12 | - "./data:/data" 13 | ports: 14 | - "0.0.0.0:8766:8766/udp" 15 | - "0.0.0.0:27016:27016/udp" 16 | - "0.0.0.0:9700:9700/udp" 17 | logging: 18 | driver: "json-file" 19 | options: 20 | max-size: "50m" -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageRules": [ 3 | { 4 | "matchManagers": ["dockerfile"], 5 | "matchUpdateTypes": ["major", "minor", "patch"], 6 | "automerge": false 7 | }, 8 | { 9 | "matchUpdateTypes": [ 10 | "major", 11 | "minor", 12 | "patch", 13 | "pin", 14 | "digest" 15 | ], 16 | "automerge": true, 17 | "automergeType": "branch" 18 | } 19 | ] 20 | } 21 | --------------------------------------------------------------------------------