How to Back Up a Rust Server on Linux
Back up a Rust server on Linux: which files matter, saving first, a tar and zstd script, rotation, off-site copies with rclone and testing a restore.
Last updated Verified on Ubuntu 26.04.1 LTS, Rust build 25582902, GNU tar 1.35, zstd 1.5.7, 2026-09-28
On this page
A Rust server backup is the install directory minus the game files: the identity folder under server/ (map, save, player databases, cfg/) plus oxide/ or carbon/ for plugins, their configs and data. Save over RCON or stop the server first, pack it with tar --zstd, keep a rolling set on the host, copy it off the box with rclone, and restore one on a test box now and then so you know it works.
What to back up
Everything that makes your server yours lives in a handful of places inside the install directory. On our test host that is /opt/rust-servers/instance-1, with +server.identity set to a folder under server/.
| Path | What it holds |
|---|---|
server/<identity>/*.map, *.sav | The generated map and the world save: bases, deployables, loot. .sav.1 and .sav.2 are the server's own rolling copies of earlier saves. |
server/<identity>/*.navmesh, *_occlusion_3.dat | Navmesh and occlusion data for the current map. The navmesh is written with every world save and read back on start, so treat it as part of the save. |
server/<identity>/*.db | SQLite databases: player.*.db (blueprints, identities, deaths, player states, tokens), clans, relationship and sv.files (images on signs). Copy each one together with its -wal file. |
server/<identity>/cfg/ | server.cfg, users.cfg (owners and moderators), bans.cfg. |
oxide/ | Plugins (plugins/), their settings (config/), their saved data and Oxide's users and groups (data/), translations (lang/). |
carbon/ | The same for Carbon: plugins/, configs/, data/, plus modules/. |
HarmonyMods/ | Harmony mods, if you use any. |
The wipe guide explains which of these a map or blueprint wipe deletes. See how to wipe a Rust server.
What to leave out
The game itself comes from SteamCMD and can be downloaded again with app_update 258550 validate, so it has no place in a backup. These are the top-level entries the Panelra agent excludes, with sizes from our test host:
| Entry | Size |
|---|---|
Bundles/ | 5.0 GB |
RustDedicated_Data/ | 708 MB |
steamclient.so, UnityPlayer.so | 36 MB and 35 MB |
libsteam_api.so, RustDedicated, runds.sh, steam_appid.txt, steamapps/ | under 1 MB together |
Leaving these out turns a 6 GB archive into a few hundred megabytes. On the test host the remaining data was 570 MB, almost all of it in server/.
One more thing to skip: files named after a seed you no longer run. After a seed change the old .navmesh and _occlusion_3.dat files stay behind, and so do .sav.1/.sav.2 if the wipe deleted only *.map and *.sav. On our host the files from two old seeds took about 330 MB. Delete them while the server is stopped, as the wipe guide describes, and your backups shrink with them.
Save first, or stop the server
A running server holds the world in memory and writes it to disk only on an autosave (server.saveinterval, 600 seconds by default) or on shutdown. A backup taken between saves is up to ten minutes old, and a copy taken while the save is being written can be torn.
You have two options:
- Hot backup. Send
server.saveover RCON and wait forSaving completein the journal (on our host it follows within a second), then run tar. The Panelra agent does the same for its backups:server.saveover RCON, a 2 second pause, then tar. Players keep playing, so a few seconds of changes can still land between the save and the copy. - Cold backup. Stop the service, confirm
systemctl show -p ActiveStatesaysinactive, copy, start. RustDedicated also saves on SIGTERM, but a hung server never gets there, so save first anyway. This is the copy to take before a wipe, an update or any manual file surgery.
Rust's RCON is WebSocket based, so you need a client that speaks it. The wipe automation guide sets up rcon-cli with a config file at /etc/rust-wipe/rcon.yaml; the script below reuses it.
A backup script with tar and zstd
GNU tar 1.35 on Ubuntu 26.04 has --zstd built in; it needs the zstd binary, which our test host already had (apt install zstd if yours does not). On the test host we packed the same data both ways: zstd took 4.3 seconds for 378 MB, gzip took 46.5 seconds for 382 MB. Both shrink the data by about a third, so pick the fast one.
Save this as /usr/local/bin/rust-backup.sh and make it executable:
#!/usr/bin/env bash
set -euo pipefail
RUST_DIR=/opt/rust-servers/instance-1
SERVICE=rust-instance-1
NAME=instance-1
DEST=/var/backups/rust # never inside RUST_DIR
KEEP_DAYS=14
RCON="rcon -c /etc/rust-wipe/rcon.yaml -e rust -t web"
mkdir -p "$DEST"
OUT="$DEST/$NAME-$(date -u +%Y%m%d-%H%M%S).tar.zst"
# 1. Flush the world to disk if the server is up.
if systemctl is-active --quiet "$SERVICE" && [ -x /usr/local/bin/rcon ]; then
$RCON "server.save" || echo "save failed, backing up the last autosave"
sleep 5
fi
# 2. Pack everything except the game files. Exit 1 = a file changed while read.
set +e
nice -n 19 ionice -c3 tar --zstd -cf "$OUT.part" -C "$RUST_DIR" \
--exclude=./Bundles --exclude=./RustDedicated_Data --exclude=./steamapps \
--exclude=./UnityPlayer.so --exclude=./steamclient.so --exclude=./libsteam_api.so \
--exclude=./RustDedicated --exclude=./steam_appid.txt --exclude=./runds.sh \
.
rc=$?
set -e
if [ "$rc" -gt 1 ]; then rm -f "$OUT.part"; echo "tar failed ($rc)"; exit "$rc"; fi
# 3. Check the archive, then publish it under its final name with a checksum.
zstd -tq "$OUT.part"
mv "$OUT.part" "$OUT"
( cd "$DEST" && sha256sum "$(basename "$OUT")" > "$(basename "$OUT").sha256" )
# 4. Local rotation.
find "$DEST" -maxdepth 1 -name "$NAME-*.tar.zst*" -mmin +$(( KEEP_DAYS * 1440 )) -delete
nice and ionice -c3 keep the backup from stealing CPU and disk time from the game. The .part name means a half-written archive is never mistaken for a good one. If tar exits with 1, it printed which file changed while it was reading; that is normal for a hot backup, and the next run will catch it.
Run it every six hours with a systemd timer. /etc/systemd/system/rust-backup.service:
[Unit]
Description=Back up Rust server instance-1
[Service]
Type=oneshot
ExecStart=/usr/local/bin/rust-backup.sh
/etc/systemd/system/rust-backup.timer:
[Unit]
Description=Back up Rust server every 6 hours
[Timer]
OnCalendar=*-*-* 00/6:15:00
Persistent=true
[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now rust-backup.timer
systemctl list-timers rust-backup.timer
Keep the backup times away from your restart and wipe times, so a backup never runs while the server is stopping or generating a map.
Rotation
At 378 MB per archive and four a day, 14 days of local backups is about 21 GB. Check that against df -h before you pick KEEP_DAYS, because a full disk will stop the server from saving. A plan that works for most community servers:
- On the host: every six hours, kept for 3 to 14 days. This covers "a plugin ate the economy data yesterday".
- Off site: every archive, kept for 30 to 60 days.
- Before every wipe: one cold backup, kept until the next wipe at least. It is the only way back to the previous map if the wipe goes wrong.
Off-site copies with rclone
A backup on the same disk dies with the disk, or with the VPS when the provider suspends it. Copy the archives to any S3-compatible storage: Cloudflare R2, Backblaze B2, Hetzner Object Storage, Wasabi or AWS S3. rclone is in the Ubuntu archive (apt install rclone).
Create a bucket and an access key that can only read and write that bucket, then create the remote. This example is for Cloudflare R2; for other services change provider (Hetzner, Wasabi, AWS or Other) and endpoint:
rclone config create offsite s3 \
provider=Cloudflare \
access_key_id=YOUR_ACCESS_KEY_ID \
secret_access_key=YOUR_SECRET_ACCESS_KEY \
endpoint=https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com \
acl=private
rclone obscures the secret in its config file, but the command stays in your shell history; run rclone config instead if you prefer the prompts. Then add these lines to the end of the backup script:
# 5. Off-site copy, then prove it arrived intact.
rclone copy "$DEST" offsite:rust-backups/$NAME --include "$NAME-*" --s3-no-check-bucket
rclone check "$DEST" offsite:rust-backups/$NAME --include "$NAME-*" --one-way
rclone copy uploads only new or changed files and never deletes anything at the destination, so local rotation does not touch the remote copies. --s3-no-check-bucket stops rclone from trying to create the bucket, which a key limited to one bucket is not allowed to do. rclone check --one-way compares the sizes and hashes of every local file with the remote copy.
Prune the remote once a day, and preview it first:
rclone delete offsite:rust-backups/instance-1 --min-age 60d --dry-run
rclone delete offsite:rust-backups/instance-1 --min-age 60d
Most providers can also expire objects with a bucket lifecycle rule, which keeps working even if the host is gone.
Restore a backup
- Pick and check the archive.
cd /var/backups/rust && sha256sum -c instance-1-20260928-120015.tar.zst.sha256must printOK. For an off-site copy,rclone copyit down first. - Stop the server with
systemctl stop rust-instance-1and wait forActiveState=inactive. Restoring under a running server is pointless: it writes its own world back on the next save. - Move the current state aside instead of deleting it, so you can undo the restore:
cd /opt/rust-servers/instance-1 mkdir -p /var/backups/rust/pre-restore mv server oxide /var/backups/rust/pre-restore/ # or carbon, if you run Carbon - Extract. The whole archive:
Or only part of it, for example just the plugin data, by naming paths as they appear intar --zstd -xf /var/backups/rust/instance-1-20260928-120015.tar.zst -C /opt/rust-servers/instance-1tar --zstd -tf:./oxide/data. - Check it will load. The identity folder must match
+server.identityin the unit. The save is namedproceduralmap.<size>.<seed>.<n>.sav, andserver.worldsizeandserver.seedinserver/<identity>/cfg/server.cfgmust match it, as must the version number for the current Rust build, or the server will generate a new map next to it. If the unit runs as a non-root user,chown -Rthe restored files to that user. - Start and watch
journalctl -u rust-instance-1 -f. A good restore showsSpawning N entities from save, thenServer startup complete. If there is noentities from saveline and the world is empty in game, the server did not find your save: check step 5 again.
If you restore a Carbon install from before a Rust update, Carbon updates its own files on the first start. A restore never touches Oxide's DLLs: they live in RustDedicated_Data/Managed, which is not in the backup. On a fresh install, and after every Rust update, install Oxide as usual. See Oxide on Linux and Carbon on Linux.
Test a restore before you need it
A backup you have never restored is a guess. Once a month, and after any change to the script:
- Extract the newest archive into a scratch directory with
tar --zstd -xf ... -C /tmp/restore-testand check thatserver/<identity>/has a.sav, theplayer.*.dbfiles andcfg/server.cfg, and thatoxide/dataorcarbon/datais there. - Better: install a second copy of the game with SteamCMD on a spare box, install Oxide there if you use it (its DLLs are not in the archive), extract the archive into it, give it different ports and start it. When it logs
Spawning N entities from save, join and look at a base you know. - Pull one archive back from the remote and run
sha256sum -con it, so you know the off-site copies work too.
Panelra backups
Panelra does all of this for you: install the agent on your Linux host and you get manual backups from the dashboard, scheduled backups with a cron expression, and an optional automatic backup before every scheduled wipe. The agent saves over RCON, packs everything except the game files listed above, records a SHA-256 checksum and uploads the archive to cloud storage, so a dead host does not take the backups with it. Old backups are deleted after the number of days you set per server. With the pre-wipe backup turned on, a forced wipe waits up to 10 minutes for its backup and then goes ahead, so a slow upload never keeps your players on the old map.
Restore is one click on a stopped server. The agent checks free disk space, downloads the archive, verifies the checksum, takes a snapshot of the current files, cleans them, extracts the backup and checks that the identity folder is there. If any step fails, it rolls back to the snapshot. See backups and recovery.
Free during the open beta. Pricing will be announced before the beta ends.
Backup checklist
- Back up
server/<identity>/,oxide/orcarbon/, andHarmonyMods/. - Exclude
Bundles/,RustDedicated_Data/,steamapps/and the Steam and Unity libraries. -
server.saveover RCON before a hot backup; stop the server before wipes and updates. - Write to a
.partfile, test it withzstd -t, then rename and add a.sha256. - Rotate locally and watch free disk space.
- Copy off site with
rclone copy, confirm withrclone check --one-way. - Keep one cold backup from before each wipe.
- Test a restore every month.
Frequently asked questions
Can I back up a Rust server while it is running?
How big is a Rust server backup?
Do I need to back up the game files?
Will an old backup load after a forced wipe update?
Skip the manual work: install the Panelra agent
Wipes, updates, restarts, plugins and crash alerts for your Rust servers, from one dashboard. One install command on your Linux host, no inbound ports for the agent.
Free during the open beta. Pricing will be announced before the beta ends.