Posted on
Artificial Intelligence

Artificial Intelligence ARK Server Backups

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Artificial Intelligence ARK Server Backups (with Bash): Smarter, Safer, and Hands-Off

If you run an ARK: Survival Evolved server, you already know the pain: world saves are huge, players are unpredictable, and a single crash can cost days of progress. Traditional “set a cron and pray” backups work—until they don’t. This post shows how to build a resilient, Bash-first backup pipeline that’s AI‑aware: it adapts backup frequency to real player activity, detects anomalies, verifies integrity, and ships your data offsite.

You’ll get:

  • A ready-to-use Bash backup script for ARK

  • Installation steps for apt, dnf, and zypper

  • Cloud sync via rclone and versioned, deduplicated storage via restic

  • Optional AI logic (local, via Ollama) to vary backup intervals and flag suspicious changes

Why AI for ARK backups?

  • Load-aware scheduling: Back up more during peak times, less during off-hours—without guessing. AI can summarize logs, predict high-activity windows, and adjust intervals.

  • Anomaly detection: Sudden drops in backup size usually mean corruption, unintended wipes, or misconfigurations. A model can flag this for you in plain language.

  • Cost control: Versioned dedup backups are cheap; useless frequent full tars are not. Smart schedules plus dedup keep you safe and thrifty.

What we’ll build

  • restic for incremental, encrypted, verifiable backups

  • rclone to sync those backups to your preferred cloud

  • A Bash script that:

    • Triggers a save (optionally via your RCON client)
    • Runs a restic backup + retention + health check
    • Optionally uses a local LLM (Ollama) to adjust the next backup interval from ARK logs
    • Syncs the repository to cloud storage

Prerequisites and installation

We’ll use restic, rclone, jq, and cron (or systemd timers). Install them with your package manager:

  • Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y restic rclone jq cron
sudo systemctl enable --now cron
  • Fedora/RHEL/CentOS Stream (dnf):
sudo dnf install -y restic rclone jq cronie
sudo systemctl enable --now crond
  • openSUSE (zypper):
sudo zypper refresh
sudo zypper install -y restic rclone jq cron
sudo systemctl enable --now cron

Optional local AI (Ollama). This uses a small, local LLM—no cloud keys needed:

curl -fsSL https://ollama.com/install.sh | sh
# Start Ollama service if not auto-started:
sudo systemctl enable --now ollama
# Pull a compact, capable model:
ollama pull llama3:8b

Note: If you don’t want AI, keep AI_MODE=off in the script below.

One-time setup

1) Choose where your ARK server data lives (example paths):

  • ARK directory: /opt/ark/ShooterGame

  • Saves: /opt/ark/ShooterGame/Saved

  • Config: /opt/ark/ShooterGame/Saved/Config/LinuxServer

2) Create a local restic repository and a password file:

sudo mkdir -p /srv/ark-backups/repo
sudo mkdir -p /srv/ark-backups/state
sudo install -m 600 /dev/null /srv/ark-backups/restic-password
echo "A-Strong-Unique-Password" | sudo tee /srv/ark-backups/restic-password >/dev/null

export RESTIC_REPOSITORY=/srv/ark-backups/repo
export RESTIC_PASSWORD_FILE=/srv/ark-backups/restic-password
restic init

3) Create and configure an rclone remote (S3, Backblaze, Google Drive, etc.):

rclone config
# Follow the prompts to create a remote, e.g. name it: arkremote
# Example backup target: arkremote:ark-backups/restic-repo

4) Verify permissions. Ensure the user that will run backups can read ARK saves and write to the repo.

The AI‑aware Bash backup script

Save as /usr/local/bin/ark-backup.sh and make it executable.

#!/usr/bin/env bash
set -euo pipefail

# ========= Config =========
# Paths
ARK_DIR="${ARK_DIR:-/opt/ark/ShooterGame}"                  # adjust to your server path
SAVES_DIR="$ARK_DIR/Saved"
CONFIG_DIR="$ARK_DIR/Saved/Config/LinuxServer"

# Restic
RESTIC_REPOSITORY="${RESTIC_REPOSITORY:-/srv/ark-backups/repo}"
RESTIC_PASSWORD_FILE="${RESTIC_PASSWORD_FILE:-/srv/ark-backups/restic-password}"

# rclone remote (set to "" to disable cloud sync)
RCLONE_REMOTE="${RCLONE_REMOTE:-arkremote:ark-backups/restic-repo}"

# State and logs
STATE_DIR="${STATE_DIR:-/srv/ark-backups/state}"
LOG_DIR="${LOG_DIR:-$STATE_DIR/logs}"
mkdir -p "$STATE_DIR" "$LOG_DIR"

# AI controls
AI_MODE="${AI_MODE:-off}"            # off | ollama
AI_MODEL="${AI_MODEL:-llama3:8b}"    # ollama model tag
DEFAULT_INTERVAL_MIN="${DEFAULT_INTERVAL_MIN:-60}"  # fallback interval
NEXT_RUN_FILE="$STATE_DIR/next_run_epoch"

# Optional pre-backup save trigger (if you have an rcon client or admin tool installed)
# Example: PRE_BACKUP_CMD="rcon-cli -a 127.0.0.1:27020 -p 'RCONPASS' command SaveWorld"
PRE_BACKUP_CMD="${PRE_BACKUP_CMD:-}"

# Retention policy for restic
RETENTION_ARGS=(
  --keep-hourly 24
  --keep-daily 7
  --keep-weekly 4
  --keep-monthly 6
)

# ========= Helpers =========
now_epoch() { date +%s; }

log() {
  echo "[$(date -Is)] $*" | tee -a "$LOG_DIR/ark-backup.log"
}

require() {
  command -v "$1" >/dev/null 2>&1 || { log "Missing dependency: $1"; exit 1; }
}

# ========= Dependencies =========
require restic
require rclone
require jq

# ========= AI interval recommendation (optional) =========
recommend_interval_minutes() {
  # Simple heuristic if AI is off: more frequent when players were active in the last 2 hours
  # You can replace this with your own logic if you don’t use AI.
  local activity_lines
  activity_lines=$(grep -h -E 'Join|Logout|SaveGame' "$SAVES_DIR"/Logs/*.log 2>/dev/null | tail -n 500 || true)

  if [[ "$AI_MODE" == "ollama" ]]; then
    command -v ollama >/dev/null 2>&1 || { log "AI_MODE=ollama but ollama not found; falling back."; AI_MODE=off; }
  fi

  if [[ "$AI_MODE" == "ollama" ]]; then
    # Compose a compact prompt; ask for a plain integer in minutes.
    local prompt
    prompt=$(cat <<'P'
You analyze ARK server log snippets that include player joins/leaves and saves.
Decide the next backup interval in minutes:

- Heavy activity -> 10-15 minutes

- Moderate -> 30-45 minutes

- Light/idle -> 60-120 minutes
Only output a single integer number of minutes. No extra text.
P
)
    local minutes
    # Send to ollama; pass logs as context
    minutes=$(printf "%s\n\nLogs:\n%s\n" "$prompt" "$activity_lines" \
      | ollama run "$AI_MODEL" 2>/dev/null \
      | tr -cd '0-9' | head -c 4)

    if [[ -n "$minutes" && "$minutes" -gt 0 ]]; then
      echo "$minutes"
      return 0
    fi
    # Fall through to heuristic on parse failure
    log "AI recommendation parse failed; using heuristic."
  fi

  # Heuristic: if we saw recent joins/logouts/saves, back up more often.
  if [[ -n "$activity_lines" ]]; then
    echo 30
  else
    echo "$DEFAULT_INTERVAL_MIN"
  fi
}

# ========= Scheduling guard =========
guard_next_run() {
  local now
  now=$(now_epoch)
  if [[ -f "$NEXT_RUN_FILE" ]]; then
    local next
    next=$(cat "$NEXT_RUN_FILE" || echo 0)
    if [[ "$now" -lt "$next" ]]; then
      log "Not time yet (next run at epoch $next). Exiting."
      exit 0
    fi
  fi
}

set_next_run() {
  local mins="$1"
  local now next
  now=$(now_epoch)
  next=$(( now + mins*60 ))
  echo "$next" > "$NEXT_RUN_FILE"
  log "Next backup scheduled in ${mins}m (epoch $next)."
}

# ========= Core backup tasks =========
trigger_save_if_configured() {
  if [[ -n "$PRE_BACKUP_CMD" ]]; then
    log "Triggering pre-backup save..."
    # shellcheck disable=SC2086
    bash -c "$PRE_BACKUP_CMD" || log "Warning: PRE_BACKUP_CMD failed; continuing."
    # Give the server a brief moment to flush
    sleep 5
  fi
}

run_backup() {
  log "Starting restic backup..."
  # Use JSON for machine-readable stats; tee to a run log
  local runlog="$LOG_DIR/backup-$(date +%s).jsonl"
  if restic backup \
      --tag ark \
      --host "$(hostname -s)" \
      --json \
      "$SAVES_DIR" "$CONFIG_DIR" | tee "$runlog"
  then
    log "Backup completed."
  else
    log "Backup failed."
    exit 2
  fi

  # Extract totals from the last JSON line with a summary
  local total_bytes files_new
  total_bytes=$(tac "$runlog" | jq -r 'select(.message_type=="summary") | .total_bytes_processed' | head -n1)
  files_new=$(tac "$runlog" | jq -r 'select(.message_type=="summary") | .files_new' | head -n1)
  log "Bytes processed: ${total_bytes:-unknown}, new files: ${files_new:-unknown}"
}

apply_retention() {
  log "Applying retention: ${RETENTION_ARGS[*]}"
  # shellcheck disable=SC2068
  restic forget ${RETENTION_ARGS[@]} --prune
  log "Retention done."
}

verify_health() {
  log "Verifying repository integrity (restic check)..."
  if restic check --read-data-subset=1/20; then
    log "Repository check OK."
  else
    log "Repository check reported issues."
  fi
}

sync_remote() {
  if [[ -n "$RCLONE_REMOTE" ]]; then
    log "Syncing repository to $RCLONE_REMOTE ..."
    rclone sync --fast-list --stats=60s "$RESTIC_REPOSITORY" "$RCLONE_REMOTE"
    log "Cloud sync complete."
  else
    log "RCLONE_REMOTE not set; skipping cloud sync."
  fi
}

# ========= Main =========
guard_next_run

trigger_save_if_configured
run_backup
apply_retention
verify_health
sync_remote

# Set next run from AI or heuristic
mins=$(recommend_interval_minutes)
set_next_run "$mins"

log "All tasks complete."

Make it executable:

sudo chmod +x /usr/local/bin/ark-backup.sh

Environment variables you may want to set system-wide (for the backup user):

  • ARK_DIR=/opt/ark/ShooterGame

  • RESTIC_REPOSITORY=/srv/ark-backups/repo

  • RESTIC_PASSWORD_FILE=/srv/ark-backups/restic-password

  • RCLONE_REMOTE=arkremote:ark-backups/restic-repo

  • AI_MODE=ollama or off

  • PRE_BACKUP_CMD="your RCON save command" (optional)

You can place them in /etc/environment or a dedicated file you source from cron.

Schedule it

Cron approach: run every 5 minutes; the script self-throttles using its state file and AI/heuristics.

crontab -e
# Every 5 minutes, with environment sourced for safety
*/5 * * * * . /etc/environment; /usr/local/bin/ark-backup.sh >> /var/log/ark-backup.cron.log 2>&1

Systemd timer (alternative): Create /etc/systemd/system/ark-backup.service

[Unit]
Description=ARK Smart Backup

[Service]
Type=oneshot
Environment=ARK_DIR=/opt/ark/ShooterGame
Environment=RESTIC_REPOSITORY=/srv/ark-backups/repo
Environment=RESTIC_PASSWORD_FILE=/srv/ark-backups/restic-password
Environment=RCLONE_REMOTE=arkremote:ark-backups/restic-repo
Environment=AI_MODE=ollama
ExecStart=/usr/local/bin/ark-backup.sh

And /etc/systemd/system/ark-backup.timer

[Unit]
Description=Run ARK Smart Backup often (self-scheduled)

[Timer]
OnCalendar=*:0/5
Persistent=true

[Install]
WantedBy=timers.target

Enable:

sudo systemctl daemon-reload
sudo systemctl enable --now ark-backup.timer

Real-world tips and examples

  • Consistent saves: Ideally, trigger ARK’s SaveWorld before backup. If you already use an RCON client, set PRE_BACKUP_CMD to run it a few seconds before restic.

  • Test restores regularly:

# List snapshots
restic snapshots

# Restore latest to a safe location for validation
restic restore latest --target ~/ark-restore-test --path "/opt/ark/ShooterGame/Saved"
  • Remote-first repositories: You can point RESTIC_REPOSITORY directly to cloud (e.g., an S3 URL) using restic’s native backends, or keep local + rclone sync as shown. Native remotes are simpler but may hit provider API limits during peaks; local+sync can be friendlier for busy servers.

  • Anomaly watch: The script logs “Bytes processed.” Sudden changes (e.g., near-zero or 10x spikes) warrant investigation. You can extend the script to compare to a rolling median and send alerts via mailx or Discord webhooks.

Troubleshooting

  • Permission denied: Make sure the backup user can read the ARK directories and write to the repo and state/log dirs.

  • Long runs: Increase DEFAULT_INTERVAL_MIN if your worlds are huge; restic dedup drastically reduces time after the first run.

  • Ollama not responding: Ensure the service is running:

systemctl status ollama

Conclusion and next steps

Backups shouldn’t be set-and-forget; they should be set-and-adapt. With a few portable tools and a pinch of AI, your ARK backups can become:

  • Safer (versioned, verified, offsite)

  • Smarter (activity-aware intervals)

  • Simpler (one Bash script, cron/systemd)

Next steps: 1) Install the tools and initialize your restic repo. 2) Drop in the script, set PRE_BACKUP_CMD if you have an RCON client, and enable cron or a timer. 3) Flip AI_MODE=ollama, pull a model, and watch your schedule auto-tune. 4) Do a test restore—then sleep better.

Have ideas for improvements, like Discord alerts or snapshot diff summaries? Add them as small functions—the script is built to be extended.