I run a Hytale server on a small Linux box, and the two things that actually keep it healthy aren't in any install guide: snapshot the world before something corrupts it, and restart it on a schedule before the memory creep gets bad. Both are systemd, no cron, no babysitting.
This assumes you already have the server installed and running under systemd. If not, start with the prep guide and mods/plugins setup.
TL;DR:
# nightly: stop, snapshot the world dir, start, push offsite
systemctl stop hytale
tar -czf /srv/backups/hytale-$(date +%F).tar.gz -C /srv/hytale world
systemctl start hytale
restic -r s3:s3.example.com/hytale-bak backup /srv/backups/hytale-$(date +%F).tar.gz
# daily restart at 06:00 via a systemd timer (below)
Details below.
Where the world lives
Find your world/save directory first — everything else hangs off it. On my box the server is unpacked under /srv/hytale and the persistent world data sits in /srv/hytale/world. Yours may differ; the rule is: back up the save/world dir and the server config, skip the redownloadable binaries.
du -sh /srv/hytale/* # find what's actually big and stateful
Don't just tar the whole install every night — the game files are dead weight you can re-fetch. Back up state, not the engine.
Take a clean snapshot
The single most important word here is clean. Copying a world while the server is mid-write gives you a half-flushed, occasionally corrupt backup that looks fine until you try to restore it. Stop the service, snapshot, start it again. The downtime is a few seconds:
#!/usr/bin/env bash
# /usr/local/bin/hytale-backup.sh
set -euo pipefail
STAMP=$(date +%F-%H%M)
DEST=/srv/backups
mkdir -p "$DEST"
systemctl stop hytale
tar -czf "$DEST/hytale-$STAMP.tar.gz" -C /srv/hytale world
systemctl start hytale
# keep 7 local, prune the rest
ls -1t "$DEST"/hytale-*.tar.gz | tail -n +8 | xargs -r rm --
echo "backup done: $DEST/hytale-$STAMP.tar.gz"
chmod +x /usr/local/bin/hytale-backup.sh
If a few seconds of downtime each night is too much for your crowd, warn players in-game first or pick an hour nobody's on. For most small servers, 03:00 is dead and nobody notices.
Push it offsite
A backup on the same disk as the server isn't a backup — it dies with the box. Send the snapshot somewhere else. I use restic to an S3/MinIO bucket because it's encrypted and deduplicated, so nightly tarballs that mostly overlap barely cost any space:
export RESTIC_REPOSITORY="s3:s3.example.com/hytale-bak"
export RESTIC_PASSWORD_FILE=/root/.restic-pass
restic backup /srv/backups
restic forget --keep-daily 7 --keep-weekly 4 --prune
Full walkthrough of that setup in /restic-backup-s3-minio-encrypted/. If you'd rather keep it dead simple, rsync to another host works too — just make sure it lands on different hardware.
Schedule it with a systemd timer
Skip cron. A systemd timer logs to the journal, won't overlap runs, and catches up if the box was off when it was due:
# /etc/systemd/system/hytale-backup.service
[Unit]
Description=Hytale world backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/hytale-backup.sh
# /etc/systemd/system/hytale-backup.timer
[Unit]
Description=Nightly Hytale backup
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now hytale-backup.timer
systemctl list-timers hytale-backup.timer
Persistent=true runs the job on next boot if the machine was asleep at 03:00. The full timer pattern (and why I dropped cron everywhere) is in /systemd-timers-instead-of-cron/.
Auto-restart on crash and on a schedule
Two different problems. Crash recovery is just the right directives in the service unit:
# /etc/systemd/system/hytale.service (the relevant lines)
[Service]
Restart=on-failure
RestartSec=15
StartLimitIntervalSec=0
Restart=on-failure brings it back if it dies, RestartSec=15 waits so you don't hammer a crash loop, and StartLimitIntervalSec=0 stops systemd from giving up after a few quick restarts.
Scheduled restart is the other half. Long-running game servers leak memory and fragment; a daily bounce during dead hours keeps RAM flat and tick rate smooth. Another tiny timer:
# /etc/systemd/system/hytale-restart.service
[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl restart hytale
# /etc/systemd/system/hytale-restart.timer
[Timer]
OnCalendar=*-*-* 06:00:00
Persistent=true
[Install]
WantedBy=timers.target
systemctl daemon-reload && systemctl enable --now hytale-restart.timer
06:00, after the 03:00 backup, before anyone's awake. If your unit uses KillSignal=SIGINT/SIGTERM with a sane TimeoutStopSec, the restart gives the server time to flush the world on its way down.
Test a restore — or it isn't a backup
The backup you never restored is a guess. Prove it once:
mkdir -p /tmp/restore-test
tar -xzf /srv/backups/hytale-2026-06-19-0300.tar.gz -C /tmp/restore-test
ls -R /tmp/restore-test/world | head
If you used restic offsite, also pull a snapshot back down and untar it — confirm the bytes survive the round trip, not just the local copy.
Gotchas
- Backing up a live world. Covered above and worth repeating: snapshot while stopped, or accept that some backups will be subtly corrupt. There's no flush-and-pause API you can trust here.
- Disk fills, server dies. Old tarballs pile up and one day the partition is full and the server won't start. The
tail -n +8 | xargs rmprune above plusrestic forgetkeeps it bounded. Watch free space. - Restart timer vs active players. A hard 06:00 restart mid-session is rude. Pick your real dead hour, and if you have a global player base, a short in-game "restarting in 60s" broadcast beforehand goes a long way.
- Early access churn. Hytale is still moving fast in early access — saves can break across server updates. Take a manual backup before every server version bump, not just the nightly one.
- Secrets in units. Don't paste your restic password or S3 keys into the
.servicefile. UseEnvironmentFile=pointing at a root-only0600file.
That's the whole maintenance story: clean nightly snapshots, encrypted offsite copy, scheduled restart, crash recovery. Set it once and the server mostly looks after itself.