├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── arkmanager-user.cfg ├── arkmanager.cfg ├── crontab ├── docker-compose.yml ├── healthcheck.sh └── run.sh /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Publish Docker image 2 | 3 | # This workflow uses actions that are not certified by GitHub. 4 | # They are provided by a third-party and are governed by 5 | # separate terms of service, privacy policy, and support 6 | # documentation. 7 | 8 | on: 9 | schedule: 10 | - cron: '16 21 * * *' 11 | push: 12 | branches: [ master ] 13 | # Publish semver tags as releases. 14 | tags: [ 'v*.*.*' ] 15 | pull_request: 16 | branches: [ master ] 17 | 18 | jobs: 19 | push_to_registries: 20 | name: Push Docker image to multiple registries 21 | runs-on: ubuntu-latest 22 | permissions: 23 | contents: read 24 | packages: write 25 | 26 | steps: 27 | - name: Check out the repo 28 | uses: actions/checkout@v3 29 | 30 | # Login against a Docker registry except on PR 31 | # https://github.com/docker/login-action 32 | - name: Log into registry Docker Hub 33 | if: github.event_name != 'pull_request' 34 | uses: docker/login-action@v2 35 | with: 36 | username: ${{ secrets.DOCKER_USERNAME }} 37 | password: ${{ secrets.DOCKER_PASSWORD }} 38 | - name: Log into registry ghcr.io 39 | if: github.event_name != 'pull_request' 40 | uses: docker/login-action@v2 41 | with: 42 | registry: ghcr.io 43 | username: ${{ github.actor }} 44 | password: ${{ secrets.GITHUB_TOKEN }} 45 | 46 | # Extract metadata (tags, labels) for Docker 47 | # https://github.com/docker/metadata-action 48 | - name: Extract metadata (tags, labels) for Docker 49 | id: meta 50 | uses: docker/metadata-action@v4 51 | with: 52 | images: | 53 | ${{ github.repository }} 54 | ghcr.io/${{ github.repository }} 55 | 56 | # Build and push Docker image with Buildx (don't push on PR) 57 | # https://github.com/docker/build-push-action 58 | - name: Build and push Docker image 59 | uses: docker/build-push-action@v3 60 | with: 61 | context: . 62 | push: ${{ github.event_name != 'pull_request' }} 63 | tags: ${{ steps.meta.outputs.tags }} 64 | labels: ${{ steps.meta.outputs.labels }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff: 7 | .idea/**/workspace.xml 8 | .idea/**/tasks.xml 9 | .idea/dictionaries 10 | 11 | # Sensitive or high-churn files: 12 | .idea/**/dataSources/ 13 | .idea/**/dataSources.ids 14 | .idea/**/dataSources.xml 15 | .idea/**/dataSources.local.xml 16 | .idea/**/sqlDataSources.xml 17 | .idea/**/dynamic.xml 18 | .idea/**/uiDesigner.xml 19 | 20 | # Gradle: 21 | .idea/**/gradle.xml 22 | .idea/**/libraries 23 | 24 | # Mongo Explorer plugin: 25 | .idea/**/mongoSettings.xml 26 | 27 | ## File-based project format: 28 | *.iws 29 | 30 | ## Plugin-specific files: 31 | 32 | # IntelliJ 33 | /out/ 34 | 35 | # mpeltonen/sbt-idea plugin 36 | .idea_modules/ 37 | 38 | # JIRA plugin 39 | atlassian-ide-plugin.xml 40 | 41 | # Crashlytics plugin (for Android Studio and IntelliJ) 42 | com_crashlytics_export_strings.xml 43 | crashlytics.properties 44 | crashlytics-build.properties 45 | fabric.properties 46 | 47 | .gitignore 48 | .idea/ 49 | Ark-docker.iml 50 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM phusion/baseimage:jammy-1.0.1 3 | # https://github.com/phusion/baseimage-docker 4 | 5 | LABEL org.opencontainers.image.authors="Richard Kuhnt " \ 6 | org.opencontainers.image.title="ARK Cluster Image" \ 7 | org.opencontainers.image.description="ARK Cluster Image" \ 8 | org.opencontainers.image.url="https://github.com/r15ch13/arkcluster" \ 9 | org.opencontainers.image.source="https://github.com/r15ch13/arkcluster" 10 | 11 | # Use baseimage-docker's init system. 12 | CMD ["/sbin/my_init"] 13 | 14 | RUN <= 2 | # comment out these values if you want to define them 3 | # inside your GameUserSettings.ini file 4 | serverMap="${SERVERMAP:=TheIsland}" # server map (default TheIsland) 5 | #serverMapModId="469987622" # Uncomment this to specify the Map Mod Id ( in http://steamcommunity.com/sharedfiles/filedetails/?id=) 6 | #ark_TotalConversionMod="496735411" # Uncomment this to specify a total-conversion mod 7 | ark_RCONEnabled="${RCON_ENABLE:=false}" # Enable RCON Protocol 8 | ark_RCONPort="${RCON_PORT:=32330}" # RCON Port 9 | ark_SessionName="${SESSION_NAME:=ARK Docker}" # if your session name needs special characters please use the .ini instead 10 | ark_Port="${GAME_PORT:=7778}" # ARK server port (default 7777) 11 | ark_QueryPort="${QUERY_PORT:=27015}" # ARK query port (default 27015) 12 | ark_ServerPassword="${SERVER_PASSWORD}" # ARK server password, empty: no password required to login 13 | ark_ServerAdminPassword="${ADMIN_PASSWORD}" # ARK server admin password, KEEP IT SAFE! 14 | ark_SpectatorPassword="${SPECTATOR_PASSWORD}" # ARK spectator password, KEEP IT SAFE! 15 | ark_ServerPVE="${SERVER_PVE:=false}" # Enable PVE (default false) 16 | ark_MaxPlayers="${MAX_PLAYERS:=15}" 17 | ark_GameModIds="${MODS}" # Uncomment to specify additional mods by Mod Id separated by commas 18 | arkopt_clusterid="${CLUSTER_ID}" 19 | arkGameUserSettingsIniFile="${GAME_USERSETTINGS_INI_PATH}" 20 | arkGameIniFile="${GAME_INI_PATH}" 21 | #ark_AltSaveDirectoryName="SotF" # Uncomment to specify a different save directory name 22 | 23 | # ARK server flags - use arkflag_=true 24 | #arkflag_OnlyAdminRejoinAsSpectator=true # Uncomment to only allow admins to rejoin as spectator 25 | #arkflag_DisableDeathSpectator=true # Uncomment to disable players from becoming spectators when they die 26 | arkflag_log=true 27 | arkflag_NoBattlEye=true 28 | arkflag_NoTransferFromFiltering=true 29 | arkopt_ShowFloatingDamageText=true 30 | 31 | # ARK server options - i.e. for -optname=val, use arkopt_optname=val 32 | #arkopt_StructureDestructionTag=DestroySwampSnowStructures 33 | 34 | # Options to automatically remove old backups to keep backup size in check 35 | # Each compressed backup is generally about 1-2MB in size. 36 | arkMaxBackupSizeMB="${MAX_BACKUP_SIZE:=500}" # Set to automatically remove old backups when size exceeds this limit 37 | # arkMaxBackupSizeGB="${MAX_BACKUP_SIZE:=1}" # Uncomment this and comment the above to specify the limit in whole GB 38 | 39 | # Update warning messages 40 | # Modify as desired, putting the %d replacement operator where the number belongs 41 | msgWarnUpdateMinutes="This ARK server will shutdown for an update in %d minutes" 42 | msgWarnUpdateSeconds="This ARK server will shutdown for an update in %d seconds" 43 | msgWarnRestartMinutes="This ARK server will shutdown for a restart in %d minutes" 44 | msgWarnRestartSeconds="This ARK server will shutdown for a restart in %d seconds" 45 | msgWarnShutdownMinutes="This ARK server will shutdown in %d minutes" 46 | msgWarnShutdownSeconds="This ARK server will shutdown in %d seconds" 47 | msgWarnCancelled="Restart cancelled by player request" 48 | -------------------------------------------------------------------------------- /arkmanager.cfg: -------------------------------------------------------------------------------- 1 | # --- SYSTEM CONFIG - DO NOT TOUCH ---# 2 | 3 | arkstChannel="master" # change it to a different branch to get non-stable versions 4 | install_bindir="/usr/bin" 5 | install_libexecdir="/usr/libexec/arkmanager" 6 | install_datadir="/usr/share/arkmanager" 7 | 8 | # config SteamCMD 9 | steamcmdroot="/home/steam/steamcmd" # path of your steamcmd instance 10 | steamcmdexec="steamcmd.sh" # name of steamcmd executable 11 | steamcmd_user="steam" # name of the system user who own steamcmd folder 12 | steamcmd_appinfocache="/home/steam/Steam/appcache/appinfo.vdf" # cache of the appinfo command 13 | 14 | # config environment 15 | arkserverroot="/ark/server" # path of your ARK server files (default ~/ARK) 16 | arkserverexec="ShooterGame/Binaries/Linux/ShooterGameServer" # name of ARK server executable 17 | arkbackupdir="/ark/backup" # path to backup directory 18 | arkautorestartfile="ShooterGame/Saved/.autorestart" # path to autorestart file 19 | arkStagingDir="/ark/staging" 20 | arkopt_ClusterDirOverride="/cluster" 21 | 22 | # config Service 23 | servicename="arkserv" # Name of the service (don't change if you don't know what are you doing) 24 | logdir="/ark/log/" # Logs path (default /var/log/arktools) 25 | 26 | # steamdb specific 27 | appid="376030" # Linux server App ID 28 | mod_appid="346110" # App ID for mods 29 | mod_branch="Windows" 30 | 31 | # Need to be true to work with UPDATEPONSTART (See #10) 32 | arkAutoUpdateOnStart="true" # set this to true if you want to always update before startup 33 | arkBackupPreUpdate="false" # set this to true if you want to perform a backup before updating 34 | arkNoPortDecrement="true" # unset this to use the old Port - 1 behaviour 35 | 36 | defaultinstance="main" 37 | 38 | # We don't use the dots because it doesn't show. 39 | progressDisplayType="spinner" 40 | 41 | source /ark/arkmanager.cfg 42 | -------------------------------------------------------------------------------- /crontab: -------------------------------------------------------------------------------- 1 | SHELL=/bin/bash 2 | # Example of job definition: 3 | # .---------------- minute (0 - 59) 4 | # | .------------- hour (0 - 23) 5 | # | | .---------- day of month (1 - 31) 6 | # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... 7 | # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat 8 | # | | | | | 9 | # * * * * * user command to be executed 10 | # Example : update every hour 11 | # 0 * * * * arkmanager update >> /ark/log/crontab.log 2>&1 12 | # Example : backup every 15min 13 | # */15 * * * * arkmanager backup >> /ark/log/crontab.log 2>&1 14 | # Example : backup every day at midnight 15 | # 0 0 * * * arkmanager backup >> /ark/log/crontab.log 2>&1 16 | # Example : Clean up backups older than 7 days and remove empty folders at 2:10am 17 | # 10 2 * * * find /ark/backup -type f -mtime +7 -delete; find /ark/backup -type d -empty -delete 18 | # WARNING : the container timezone is maybe not your current timezone 19 | # You can sync them with option -v /etc/localtime:/etc/localtime:ro or -e "TZ=UTC" 20 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | island: 5 | image: r15ch13/arkcluster:latest 6 | deploy: 7 | mode: global 8 | environment: 9 | CRON_AUTO_UPDATE: "0 */3 * * *" 10 | CRON_AUTO_BACKUP: "0 */1 * * *" 11 | UPDATEONSTART: 1 12 | BACKUPONSTART: 1 13 | BACKUPONSTOP: 1 14 | WARNONSTOP: 1 15 | USER_ID: 1000 16 | GROUP_ID: 1000 17 | TZ: "UTC" 18 | MAX_BACKUP_SIZE: 500 19 | SERVERMAP: "TheIsland" 20 | SESSION_NAME: "ARK Cluster TheIsland" 21 | MAX_PLAYERS: 15 22 | RCON_ENABLE: "True" 23 | QUERY_PORT: 15000 24 | GAME_PORT: 15002 25 | RCON_PORT: 15003 26 | SERVER_PVE: "False" 27 | SERVER_PASSWORD: "" 28 | ADMIN_PASSWORD: "keepmesecret" 29 | SPECTATOR_PASSWORD: "keepmesecret" 30 | MODS: "731604991" 31 | CLUSTER_ID: "myclusterid" 32 | GAME_USERSETTINGS_INI_PATH: "/cluster/myclusterid.GameUserSettings.ini" 33 | GAME_INI_PATH: "/cluster/myclusterid.Game.ini" 34 | KILL_PROCESS_TIMEOUT: 300 35 | KILL_ALL_PROCESSES_TIMEOUT: 300 36 | volumes: 37 | - data_island:/ark 38 | - cluster:/cluster 39 | ports: 40 | - "15000-15003:15000-15003/udp" 41 | 42 | valguero: 43 | image: r15ch13/arkcluster:latest 44 | deploy: 45 | mode: global 46 | environment: 47 | CRON_AUTO_UPDATE: "15 */3 * * *" 48 | CRON_AUTO_BACKUP: "15 */1 * * *" 49 | UPDATEONSTART: 1 50 | BACKUPONSTART: 1 51 | BACKUPONSTOP: 1 52 | WARNONSTOP: 1 53 | USER_ID: 1000 54 | GROUP_ID: 1000 55 | TZ: "UTC" 56 | MAX_BACKUP_SIZE: 500 57 | SERVERMAP: "Valguero_P" 58 | SESSION_NAME: "ARK Cluster Valguero" 59 | MAX_PLAYERS: 15 60 | RCON_ENABLE: "False" 61 | QUERY_PORT: 15010 62 | GAME_PORT: 15012 63 | RCON_PORT: 15013 64 | SERVER_PVE: "False" 65 | SERVER_PASSWORD: "" 66 | ADMIN_PASSWORD: "keepmesecret" 67 | SPECTATOR_PASSWORD: "keepmesecret" 68 | MODS: "731604991" 69 | CLUSTER_ID: "myclusterid" 70 | GAME_USERSETTINGS_INI_PATH: "/cluster/myclusterid.GameUserSettings.ini" 71 | GAME_INI_PATH: "/cluster/myclusterid.Game.ini" 72 | KILL_PROCESS_TIMEOUT: 300 73 | KILL_ALL_PROCESSES_TIMEOUT: 300 74 | volumes: 75 | - data_valguero:/ark 76 | - cluster:/cluster 77 | ports: 78 | - "15010-15013:15010-15013/udp" 79 | 80 | volumes: 81 | data_island: 82 | data_valguero: 83 | cluster: -------------------------------------------------------------------------------- /healthcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # shellcheck source=/dev/null 4 | source /etc/container_environment.sh 5 | source /etc/arkmanager/arkmanager.cfg 6 | 7 | SERVER_PID=$(pidof ShooterGameServer) 8 | 9 | [[ -n "$SERVER_PID" ]] && echo -n "Running: Yes" || echo -n "Running: No" 10 | if [ -e /ark/server/.installing-ark ]; then 11 | echo " | Status: Installing ARK" 12 | exit 0 13 | fi 14 | if [ -e /ark/server/.installing-mods ]; then 15 | echo " | Status: Installing Mods" 16 | exit 0 17 | fi 18 | [[ -n "$SERVER_PID" ]] && echo -n " | PID: ${SERVER_PID}" 19 | 20 | [[ -n "$SERVER_PID" && $(runuser -l steam -c "lsof -wti udp:$QUERY_PORT") -eq "$SERVER_PID" ]] && echo -n " | Query Port: Open" || echo -n " | Query Port: Closed" 21 | [[ -n "$SERVER_PID" && $(runuser -l steam -c "lsof -wti udp:$GAME_PORT") -eq "$SERVER_PID" ]] && echo -n " | Game Port: Open" || echo -n " | Game Port: Closed" 22 | [[ -n "$SERVER_PID" && $(runuser -l steam -c "lsof -wti udp:$RCON_PORT") -eq "$SERVER_PID" ]] && echo " | RCON Port: Open" || echo " | RCON Port: Closed" 23 | 24 | if [ -e /ark/server/.stopping-server ]; then 25 | echo " | Status: Stopping" 26 | exit 0 27 | fi 28 | 29 | [[ -n "$SERVER_PID" ]] && exit 0 || exit 1 30 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # shellcheck source=/dev/null 4 | source /etc/container_environment.sh 5 | 6 | function log { echo "$(date +%Y-%m-%dT%H:%M:%SZ): $*"; } 7 | 8 | log "###########################################################################" 9 | log "# Started - $(date)" 10 | log "# Server - ${SESSION_NAME}" 11 | log "# Cluster - ${CLUSTER_ID}" 12 | log "# User - ${USER_ID}" 13 | log "# Group - ${GROUP_ID}" 14 | log "###########################################################################" 15 | [ -p /tmp/FIFO ] && rm /tmp/FIFO 16 | mkfifo /tmp/FIFO 17 | 18 | rm -f /ark/server/.stopping-server 19 | rm -f /ark/server/.installing-ark 20 | rm -f /ark/server/.installing-mods 21 | 22 | export TERM=linux 23 | 24 | function stop { 25 | touch /ark/server/.stopping-server 26 | if [ "${BACKUPONSTOP}" -eq 1 ] && [ "$(ls -A /ark/server/ShooterGame/Saved/SavedArks)" ]; then 27 | log "Creating Backup ..." 28 | arkmanager backup --cluster 29 | fi 30 | if [ "${WARNONSTOP}" -eq 1 ]; then 31 | arkmanager stop --warn 32 | else 33 | arkmanager stop 34 | fi 35 | rm -f /ark/server/.stopping-server 36 | exit 37 | } 38 | 39 | # Change the USER_ID if needed 40 | if [ ! "$(id -u steam)" -eq "$USER_ID" ]; then 41 | log "Changing steam uid to $USER_ID." 42 | usermod -o -u "$USER_ID" steam 43 | fi 44 | # Change gid if needed 45 | if [ ! "$(id -g steam)" -eq "$GROUP_ID" ]; then 46 | log "Changing steam gid to $GROUP_ID." 47 | groupmod -o -g "$GROUP_ID" steam 48 | fi 49 | 50 | [ ! -d /ark/log ] && mkdir /ark/log 51 | [ ! -d /ark/backup ] && mkdir /ark/backup 52 | [ ! -d /ark/staging ] && mkdir /ark/staging 53 | [ ! -d /ark/steam ] && mkdir /ark/steam 54 | [ ! -d /ark/.steam ] && mkdir /ark/.steam 55 | 56 | if [ -f "/usr/share/zoneinfo/${TZ}" ]; then 57 | log "Setting timezone to ${TZ} ..." 58 | ln -sf "/usr/share/zoneinfo/${TZ}" /etc/localtime 59 | fi 60 | 61 | if [ ! -f /etc/cron.d/arkupdate ]; then 62 | log "Adding update cronjob (${CRON_AUTO_UPDATE}) ..." 63 | echo "$CRON_AUTO_UPDATE steam bash -l -c 'arkmanager update --dots --update-mods --warn --ifempty --saveworld --backup >> /ark/log/ark-update.log 2>&1'" > /etc/cron.d/arkupdate 64 | fi 65 | 66 | if [ ! -f /etc/cron.d/arkbackup ]; then 67 | log "Adding backup cronjob (${CRON_AUTO_BACKUP}) ..." 68 | echo "$CRON_AUTO_BACKUP steam bash -l -c 'arkmanager backup --cluster >> /ark/log/ark-backup.log 2>&1'" > /etc/cron.d/arkbackup 69 | fi 70 | 71 | # We overwrite the default file each time 72 | cp /home/steam/arkmanager-user.cfg /ark/default/arkmanager.cfg 73 | 74 | # Copy default arkmanager.cfg if it doesn't exist 75 | [ ! -f /ark/arkmanager.cfg ] && cp /home/steam/arkmanager-user.cfg /ark/arkmanager.cfg 76 | if [ ! -L /etc/arkmanager/instances/main.cfg ]; then 77 | rm /etc/arkmanager/instances/main.cfg 78 | ln -s /ark/arkmanager.cfg /etc/arkmanager/instances/main.cfg 79 | fi 80 | 81 | # Put steam owner of directories (if the uid changed, then it's needed) 82 | chown -R steam:steam /ark /home/steam /cluster 83 | log "###########################################################################" 84 | 85 | if [ ! -d /ark/server ] || [ ! -f /ark/server/version.txt ]; then 86 | log "No game files found. Installing..." 87 | mkdir -p /ark/server/ShooterGame/Saved/SavedArks 88 | mkdir -p /ark/server/ShooterGame/Content/Mods 89 | mkdir -p /ark/server/ShooterGame/Binaries/Linux 90 | touch /ark/server/ShooterGame/Binaries/Linux/ShooterGameServer 91 | chown -R steam:steam /ark/server 92 | touch /ark/server/.installing-ark 93 | arkmanager install --dots 94 | rm -f /ark/server/.installing-ark 95 | else 96 | if [ "${BACKUPONSTART}" -eq 1 ] && [ "$(ls -A /ark/server/ShooterGame/Saved/SavedArks/)" ]; then 97 | log "Creating Backup ..." 98 | arkmanager backup --cluster 99 | fi 100 | fi 101 | 102 | log "###########################################################################" 103 | log "Installing Mods ..." 104 | if ! arkmanager checkmodupdate --revstatus; then 105 | touch /ark/server/.installing-mods 106 | arkmanager installmods --dots 107 | rm -f /ark/server/.installing-mods 108 | fi 109 | 110 | log "###########################################################################" 111 | log "Launching ark server ..." 112 | if [ "${UPDATEONSTART}" -eq 1 ]; then 113 | arkmanager start 114 | else 115 | arkmanager start -noautoupdate 116 | fi 117 | 118 | # Stop server in case of signal INT or TERM 119 | log "###########################################################################" 120 | log "Running ... (waiting for INT/TERM signal)" 121 | trap stop INT 122 | trap stop TERM 123 | 124 | read -r < /tmp/FIFO & 125 | wait 126 | --------------------------------------------------------------------------------