The night your host's disk dies is the worst possible time to learn that your backups don't restore. And most don't: the archive was written while the server was still flushing region files, so half the .mca files inside are truncated. The world loads, but chunks come back as freshly generated terrain — or the server crashes on boot with Failed to read chunk. You had backups for eight months. You had usable backups for zero.
This guide builds a backup setup that survives the only test that matters: an actual restore. The save-off trick that prevents corruption, a cron script for VPS setups, offsite copies with restic, a plugin route for shared hosting without SSH, and the 15-minute monthly drill that proves the whole chain. Everything here applies whether you're still on Paper 1.21.x or the new 26.x releases.
save-off + save-all flush first. Back up the worlds, plugins/, and your configs; skip logs, caches, and map tiles. Ship an encrypted copy offsite (from $6/TB/month) and restore-test monthly. For the rest of your hosting bill, see what a server really costs in 2026.
Why most Minecraft server backups are corrupt
A running server holds loaded chunks in memory and writes them to region files (world/region/*.mca) on its own schedule — an autosave roughly every five minutes by default, plus continuous writes as chunks unload. If your backup job copies a region file mid-write, you archive a file that's internally inconsistent. tar won't complain. The upload won't complain. You find out at restore time, when chunks regenerate as empty terrain or the server refuses to start.
The fix is two console commands before the copy and one after:
save-off # stop the server writing world files
save-all flush # force everything in memory onto disk, now
# ...copy the files here...
save-on # resume normal saving
save-off doesn't pause the game — players keep playing with zero lag. The server just holds world writes in memory until save-on. Every method below is built around this window; any method that isn't (including "I just zip the folder in FileZilla while it runs") produces archives you can't trust.
What to back up — and what to skip
Copy these, always:
world/,world_nether/,world_the_end/— Paper and Spigot split dimensions into three folders; vanilla keeps everything insideworld/. Player inventories ride along inworld/playerdata/.plugins/— not just the JARs, the data: your LuckPerms database, Essentials homes, quest progress, andplugins/Votifier/rsa/. Lose those keys and you're regenerating and re-registering on every toplist (see our NuVotifier setup guide).server.properties,bukkit.yml,spigot.yml, and theconfig/folder (Paper's own configs live there)whitelist.json,ops.json,banned-players.json,banned-ips.json
Skip these — large, regenerable, or both:
logs/,crash-reports/,cache/,libraries/,versions/- Dynmap or BlueMap tile folders — often 10–50 GB of renders the plugin will happily redraw
- The server JAR itself. Instead, write the exact build into a
VERSION.txt("Paper 1.21.11, build 88") so restore day starts with a clean re-download — our server JARs page has every version.
One trap that bites later: if LuckPerms, CoreProtect, or your economy runs on MySQL instead of flat files, none of that data is in the world folder. Add one line to your backup: mysqldump -u mc -p minecraft | gzip > db_backup.sql.gz. And decide consciously about CoreProtect — its database routinely passes 20 GB and can dwarf the world itself. Seven days of block-log history is worth storing; six months of it is a storage bill.
Method 1: automatic backups with cron (VPS and dedicated)
This assumes your server runs in a screen session named mc — the most common self-hosted setup. Save as /home/mc/mc-backup.sh:
#!/bin/bash
SERVER_DIR="/home/mc/server"
BACKUP_DIR="/home/mc/backups"
STAMP=$(date +%F_%H-%M)
cmd() { screen -S mc -p 0 -X stuff "$1$(printf '\r')"; }
# re-enable saving even if this script dies halfway
trap 'cmd "save-on"' EXIT
cmd "save-off"
cmd "save-all flush"
sleep 15 # let the flush hit disk; use 60+ for 10 GB+ worlds
mkdir -p "$BACKUP_DIR"
tar -czf "$BACKUP_DIR/mc_$STAMP.tar.gz" \
-C "$SERVER_DIR" \
world world_nether world_the_end plugins config \
server.properties bukkit.yml spigot.yml \
whitelist.json ops.json banned-players.json banned-ips.json
# keep 7 days locally; offsite storage handles longer history
find "$BACKUP_DIR" -name "mc_*.tar.gz" -mtime +7 -delete
Make it executable (chmod +x mc-backup.sh) and schedule it for your quietest hour:
crontab -e
# daily at 04:30
30 4 * * * /home/mc/mc-backup.sh >> /home/mc/backups/backup.log 2>&1
The line that earns its keep is the trap. Without it, a script that dies between save-off and save-on leaves the server silently not saving — players build for hours, the server restarts, and everything since the crash is gone. With it, save-on fires no matter how the script exits.
Running under systemd instead of screen? Enable RCON in server.properties (enable-rcon=true, set a strong rcon.password) and swap the cmd function for:
cmd() { mcrcon -H 127.0.0.1 -P 25575 -p "your-rcon-password" "$1"; }
Offsite backups with restic: the 3-2-1 setup
A tarball on the same disk as the server protects you from your own mistakes, not from hardware failure or a host that disappears. The rule worth following is 3-2-1: three copies, two different media, one offsite. For a Minecraft server that means live files, local tarballs, and an encrypted offsite repository.
restic (0.19.1 as of July 2026) is the right tool for the offsite leg: it deduplicates — thirty daily snapshots of a 10 GB world don't cost 300 GB, they cost roughly one world plus whatever changed — encrypts everything by default, and prunes old snapshots by policy. Your distro's package may lag behind; run restic self-update after installing.
# one-time setup
export RESTIC_REPOSITORY="sftp:u123456@u123456.your-storagebox.de:mc-backups"
export RESTIC_PASSWORD="a-long-passphrase-stored-somewhere-safe"
restic init
Then replace (or follow) the tar line in Method 1 — inside the same save-off window — with:
restic backup "$SERVER_DIR" \
--exclude logs --exclude cache --exclude crash-reports \
--exclude libraries --exclude versions
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
That forget line is your retention policy as a decision rule: every day for a week, a weekly for a month, a monthly for half a year. It matches how disasters actually get discovered — griefing and dupe damage usually surfaces one to fourteen days after it happened, not the same night.
Two more commands close the gap between "the backup ran" and "the backup is readable". Put restic check --read-data-subset=5% in a weekly cron — it downloads and verifies a random 5% of the repository, catching silent corruption without paying a full restore's bandwidth. For the local tarballs, add gzip -t "$BACKUP_DIR/mc_$STAMP.tar.gz" || echo "BACKUP BROKEN" | mail -s "backup failed" you@example.com to the Method 1 script, so a truncated archive pages you instead of hiding for months.
Where to point the repository, at July 2026 prices:
- Hetzner Storage Box BX11 — 1 TB for €3.20/month, unlimited traffic, speaks SFTP so the repository URL above works unchanged. The default pick.
- Backblaze B2 — $6/TB/month ($0.006/GB) with free egress up to 3x your stored volume, so even a full-server restore download costs nothing. Use
restic -r b2:your-bucket:mcwith your B2 application keys.
Either way, a 10–15 GB survival server with six months of deduplicated history lands well under $1/month — the cheapest line in your entire server budget.
Backups on shared hosting (no SSH, no cron)
On typical shared Minecraft hosting you can't install restic or edit a crontab. You have two levers:
Panel backups. Most hosts run Pterodactyl, and its Backups tab genuinely works — but read the fine print. Slots are usually capped at one to three, and unless your host ships backups to external storage, they live on the same machine as your server. Treat panel backups as "undo a bad plugin update", not as disaster recovery.
DriveBackupV2 (free; 1.8.1 as of early 2026) runs as a plugin, so it works anywhere you can upload a JAR. It triggers a world save, zips your folders on a schedule, and uploads to Google Drive, OneDrive, Dropbox, or any SFTP box — real offsite copies with zero console access:
- Drop the JAR into
plugins/and restart. - In
plugins/DriveBackupV2/config.yml, setdelay: 720(minutes between backups — twice a day) andkeep-count: 14. - Run
/drivebackup linkaccount googledrivein-game as op and follow the device-code prompt.
Zipping a big world on shared CPU causes a visible lag spike, so schedule around your dead hours and resist backing up hourly out of paranoia — twice a day plus a panel snapshot before every plugin change covers a small server.
The restore test: 15 minutes a month, non-negotiable
An untested backup is a hope, not a backup. Once a month:
- Pull the latest snapshot to your PC or a scratch VPS:
restic restore latest --target ./restore-test, or untar the newest tarball. - Add a matching server JAR — same software, same version as production. That's what
VERSION.txtwas for, and it's one more reason to run maintained software (Paper vs Spigot vs Purpur vs Folia). - Start it —
java -Xmx2G -jar paper.jar --nogui— and join vialocalhost. - Check three things: the spawn area is intact (region files survived), a chest you know is full still has its items (block entities survived), and your rank and permissions work (plugin data survived).
Pass all three and the entire chain — save-off, copy, upload, retention — is proven. Fail, and you found out on a quiet Tuesday afternoon instead of the night the host's RAID died.
world/playerdata/<uuid>.dat (map names to UUIDs via usercache.json). Pull just that file from a snapshot and copy it in while the player is offline — restore it while they're online and their in-memory data overwrites your work the moment they log out.
Your world is safe — now put it in front of players
A disaster plan matters most when there are players who'd notice the downtime. If your server isn't listed yet, add it to the toplist — free, five minutes, and it starts collecting votes immediately. Already listed? Point the server status checker at your address after your next restart to confirm players see you online, because a server that's down doesn't just lose players — it slides down the rankings while you sleep.