A file named backup-2026-08-29.tar.zst can still be useless.
It may have been created while chunks were changing, may exclude a plugin database, may be truncated, or may be impossible to restore without overwriting the only surviving copy of your server.
A backup becomes trustworthy only when you can answer three questions:
- Did it capture every piece of state required to rebuild the server?
- Can you prove the archive is intact?
- Have you restored it into a clean environment?
PaperMC's own update guide recommends backing up world folders, server configuration, plugin configuration, and plugin JARs, while keeping multiple recovery points. Here is a practical workflow for a Linux VPS.
1. Define the recovery set
For a typical Paper or Purpur server, include:
- every world directory—not just a folder literally named
world; -
server.properties,bukkit.yml,spigot.yml,commands.yml, andpermissions.yml; - the Paper
config/directory; - plugin JARs and their data under
plugins/; - startup scripts, service units, and any operational documentation needed to launch the server;
- separate dumps for MySQL, PostgreSQL, or other external databases used by plugins.
Do not guess world names. Check level-name and look for level.dat files:
grep '^level-name=' /srv/paper/server.properties
find /srv/paper -maxdepth 4 -name level.dat -print
Also remember that a filesystem archive cannot magically capture a remote database. If a plugin stores economy, permissions, claims, or player data outside the server directory, add a database-native dump to the same recovery point.
2. Make the server state consistent
The safest method is boring and effective: stop the server, create the backup, then start it again.
sudo systemctl stop paper
# create and verify the backup here
sudo systemctl start paper
If you cannot accept downtime, coordinate a live backup through RCON:
- run
save-off; - run
save-all flush; - create the snapshot or archive;
- always run
save-on, including on failure.
That reduces world-file inconsistency, but it does not guarantee transaction consistency for every plugin or external database. A storage snapshot plus plugin-aware database dumps is stronger than copying a busy directory.
3. Write the archive outside the server directory
This example assumes the server is stopped or safely quiesced. The temporary and final files live in the same backup directory, so the final rename is atomic on that filesystem.
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
SERVER_DIR=/srv/paper
BACKUP_DIR=/var/backups/paper
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
TMP="$BACKUP_DIR/.paper-$STAMP.tar.zst.tmp"
FINAL="$BACKUP_DIR/paper-$STAMP.tar.zst"
mkdir -p "$BACKUP_DIR"
test -f "$SERVER_DIR/server.properties"
find "$SERVER_DIR" -maxdepth 4 -name level.dat -print | grep -q .
trap 'rm -f -- "$TMP"' EXIT
tar \
--numeric-owner \
--xattrs \
--acls \
-C "$SERVER_DIR" \
--exclude='./cache' \
-I 'zstd -T0 -6' \
-cf "$TMP" \
.
mv -- "$TMP" "$FINAL"
(
cd "$BACKUP_DIR"
sha256sum "$(basename "$FINAL")" > "$(basename "$FINAL").sha256"
)
trap - EXIT
printf 'Created %s\n' "$FINAL"
Keep the backup directory outside SERVER_DIR; otherwise, a later run can accidentally archive older backups into the new one.
An archive-level SHA-256 checksum detects truncation or later byte changes. For stronger auditing, also create a per-file manifest before packaging, especially if you need to identify exactly which restored file changed.
4. Verify immediately
Exit code zero from tar is useful, but it is not a restore test. At minimum, verify both the checksum and the archive index:
cd /var/backups/paper
sha256sum -c paper-20260829T120000Z.tar.zst.sha256
tar -I zstd -tf paper-20260829T120000Z.tar.zst >/dev/null
Add monitoring for:
- age of the most recent successful backup;
- unexpected changes in archive size;
- checksum or archive-listing failures;
- free space in the backup destination;
- overlapping jobs—use
flockso two backup runs cannot collide.
A zero-byte file with a fresh timestamp is not a successful backup.
5. Run a restore drill into an empty directory
Never test by extracting over production.
ARCHIVE=/var/backups/paper/paper-20260829T120000Z.tar.zst
RESTORE_ROOT=$(mktemp -d /tmp/paper-restore.XXXXXX)
tar -I zstd -xf "$ARCHIVE" -C "$RESTORE_ROOT"
test -f "$RESTORE_ROOT/server.properties"
find "$RESTORE_ROOT" -maxdepth 4 -name level.dat -print
find "$RESTORE_ROOT/plugins" -maxdepth 2 -type f | head
Next, compare the recovered files with your documented recovery set. Restore database dumps into an isolated database. If you perform a startup test, use a separate VM, container, or blocked network namespace so the recovered server cannot bind production ports or accept real players.
A scheduled backup without a scheduled restore drill is only half-automated.
6. Restore production with guardrails
When an incident happens:
- stop the running server;
- preserve a safety snapshot of its current state;
- verify the selected backup and its checksum;
- extract into a new, empty target directory;
- restore external databases;
- check ownership and permissions;
- switch the service to the recovered directory;
- start the server and inspect logs before admitting players.
Do not extract directly into a damaged live directory. Mixing old and restored files can create a state that never existed at any point in time.
Paper's migration documentation also reinforces an important rule: stop the server and make a complete backup before moving data or changing server software.
7. Keep more than one recovery path
A practical retention plan might keep hourly, daily, and weekly recovery points. Copy at least one verified set to a different storage system or provider, ideally with versioning or immutable retention.
Test the off-site path too. “Uploaded successfully” does not prove that credentials, permissions, download speed, decryption keys, and restore instructions will work during an outage.
Write down two targets:
- RPO: how much recent game progress you can afford to lose;
- RTO: how long the server can remain unavailable.
Those numbers should determine backup frequency and how often you rehearse recovery.
The short checklist
Before calling the job finished, confirm:
- the server was stopped or writes were coordinated;
- all worlds, configs, plugins, and external databases were captured;
- the archive was finalized atomically;
- checksum and archive listing passed;
- retention removed only backups that were safe to expire;
- another copy exists off the VPS;
- a clean restore drill succeeded.
Free 60-second check: Run the Restore Readiness Checker before changing your setup. It scores six recovery controls and shows the gaps immediately; no purchase is required.
Disclosure: I built PaperVault Ops, a one-time paid CLI toolkit for Paper/Purpur servers that automates backup, SHA-256 verification, guarded restore, retention, locking, and optional RCON save coordination. Delivery is automatic after payment. The workflow above is complete and does not require the product.
What is the last failure your Minecraft backup process actually detected—not merely the last archive it created?
Top comments (0)