The reliable way to get a game server's world into S3 storage every night is a small job on a machine you control that pulls the world over SFTP and pushes it to a bucket, timed a few minutes after the server has been told to save. rclone does both halves in one command, because it speaks SFTP and S3 natively; restic adds encryption and deduplication if you want months of history in little space. The panel's own backups stay your first line - they are quick to take and one button to restore - and the S3 copy is the one that survives the things panel backups do not: a deleted server, a mistake that was backed up over, or an account you can no longer reach. This post builds that job end to end: what to copy, how to get a clean copy, how to keep history without versioning, how to prune, and how to prove it restores.
Why a second copy, and what it protects against#
Panel backups and an S3 copy fail in different ways, which is the whole reason to have both.
| Risk | Panel backup | Copy in S3 storage | Copy at home |
|---|---|---|---|
| Griefing, bad plugin, corrupt save | Yes | Yes | Yes |
| Backup slots rotated past the good copy | Only if locked | Yes, with longer retention | Yes |
| Server deleted (backups go with it) | No | Yes | Yes |
| Loss of the whole location | Depends | No, if in the same location | Yes |
| You lose access to the hosting account | No | Only if it is a separate account | Yes |
On RE:NODE, game plans include backup slots that are stored off the machine they protect, can be locked against rotation and restore with a button - but deleting a server deletes its backups, locked ones included. A copy in a bucket outlives that. Be honest about the other row, though: RE:NODE's S3 storage keeps one copy of your data on NVMe in one location, Germany, the same place as the game servers. It protects against deletion and mistakes, not against losing the site. For a world you would be heartbroken to lose, the third column matters too, and the same rclone job can drop a copy on your own disk. Backups that actually restore covers the 3-2-1 reasoning in full, and S3 storage sizing and the 3-2-1 rule applies it to buckets.
The shape of the setup#
A game server on a panel is a container running the game, not a general-purpose machine: you get a console, a file manager, SFTP and a scheduler that runs console commands, backups and power actions - not arbitrary shell scripts. So the copy job runs somewhere else and reaches in over SFTP.
The puller can be anything that runs on a timer: a Linux VDS, a home server or Raspberry Pi, or a Windows PC that is on at night. It needs rclone, the game server's SFTP details, and the bucket's keys. It never needs to run a game or keep files between runs unless you choose restic, which keeps a small cache.
If the game runs on a VDS or a machine of your own instead, skip the SFTP half: the job runs on the same machine and reads the world folder directly.
What to copy#
Copy state and configuration; skip anything that can be downloaded again. The world folder is usually megabytes to a few gigabytes, while the game files around it are often tens of gigabytes that SteamCMD will reinstall in minutes.
| Game | Copy | Skip |
|---|---|---|
| Minecraft (Paper) | world*/, plugins/, server.properties, *.json lists | cache/, libraries/, versions/, server jar |
| Valheim | the save folder's worlds_local/, the three list files | the game install |
| Palworld | Pal/Saved/ | everything else |
| Project Zomboid | Zomboid/Saves/, Zomboid/db/, Zomboid/Server/ | the game install, Zomboid/Logs/ |
| Terraria | .wld files, serverconfig.txt, tshock/ | the server binaries |
| Factorio | saves/, data/server-settings.json, mods/ | the game install |
These paths move if the server is started with a custom save directory, so check yours against the startup line. Game server backup strategy has the longer list, including the games where the obvious folder is not the whole story - Project Zomboid's player database being the classic.
Write the choice down as an rclone filter file. It doubles as documentation of what your backup actually contains:
+ /world/**+ /world_nether/**+ /world_the_end/**+ /plugins/**+ /server.properties+ /*.json- /plugins/*.jar.old- /plugins/**/logs/**- *Rules are read top to bottom, the first match wins, and the final - * excludes everything not listed. Keeping plugin jars in the copy is deliberate: a world restored next to a newer plugin version is a common way to break it, and the exact jar you were running may not be downloadable later.
Setting up the rclone remotes#
Install rclone on the puller (sudo apt install rclone is often old; the install script or a release binary from rclone.org gets the current version), then define two remotes - one for the game server's SFTP, one for the storage.
[mc]type = sftphost = sftp.example-node.netport = 2022user = yourname.a1b2c3d4pass = <output of: rclone obscure 'your-sftp-password'>[store]type = s3provider = Otheraccess_key_id = AKIA...secret_access_key = ...endpoint = https://s3.example.comregion = us-east-1force_path_style = trueTake the SFTP host, port and username exactly as the panel shows them for that server - on Pterodactyl-based panels the username carries a server suffix and the port is usually not 22. The pass field must hold the output of rclone obscure, not the plain password. rclone obscure is reversible encoding, not encryption, so protect the file itself with chmod 600. SFTP and the file manager explains where the credentials come from.
For the storage remote, provider = Other is the generic S3-compatible setting and force_path_style = true is already rclone's default. The endpoint is the HTTPS hostname you pointed at the storage plan's proxy slot; the raw plain-HTTP port works too, but then your world travels unencrypted. Test both remotes before anything else:
$ rclone lsd mc:/$ rclone ls mc:/ --filter-from minecraft.filter | head$ rclone lsd store:$ rclone mkdir store:game-backupsThe second line is the important one: it lists exactly the files the backup will take. If the world folder is not in that list, nothing after this point matters. rclone with S3 storage covers remotes, flags and bandwidth limits in more depth.
Getting a clean copy: save first#
Most games hold the world in memory and write it on a timer. Copy files while the game is halfway through writing and you get a backup that looks complete and does not load. The answer is to tell the game to save shortly before the copy starts, using the panel's scheduler.
On RE:NODE the Schedules tab runs ordered tasks with delays from a cron expression. For Minecraft, a nightly schedule at 03:55 would be:
Task 1 command save-offTask 2 command save-all flush (delay 5 s)Task 3 command save-on (delay 600 s)save-off stops autosaves so the game does not start rewriting region files mid-copy, save-all flush writes everything to disk and waits for it, and save-on re-enables autosave ten minutes later, after the puller has finished at 04:00. For a world that copies in a minute, ten minutes is generous; for a multi-gigabyte world, time a run and widen the gap. Other games have their own save command - save in Project Zomboid and Terraria, saveworld in 7 Days to Die, /server-save in Factorio - and some, like Valheim and DayZ, have no server console command and are safest copied from a scheduled panel backup or after a clean restart. Scheduled tasks worth having and cron expressions explained cover the scheduler.
The puller's clock and the panel's schedule must agree on the time zone. Write both in UTC, or check what each one assumes, before trusting a five-minute gap.
Keeping history without versioning#
A single rclone sync keeps the bucket identical to the server - which means that when the world gets griefed at 21:00, the 04:00 sync faithfully copies the griefed world over the good one. A backup needs history. Without bucket versioning to lean on, there are three ways to get it.
Dated full copies. Each night goes into its own prefix. Simple, obvious to restore, and costs a full world's size per day.
$ rclone copy mc:/ store:game-backups/mc/daily/$(date -u +%F) \ --filter-from minecraft.filter --transfers 4 --log-file /var/log/mc-backup.logSync with a backup directory. The bucket holds one current copy, and every file that sync would overwrite or delete is moved into a dated folder first. History costs only the files that changed, which for a Minecraft world is the region files players actually visited.
$ rclone sync mc:/ store:game-backups/mc/current \ --backup-dir store:game-backups/mc/changed/$(date -u +%F) \ --filter-from minecraft.filterRestoring a past day this way means taking current and laying the dated folders back over it, newest first down to the day you want - possible, but fiddly under pressure.
restic. Pull the files to a local staging folder with rclone, then let restic take a snapshot to the bucket. restic deduplicates at the chunk level and encrypts everything, so thirty daily snapshots of a world that changes a little each day cost little more than one. Restoring any snapshot is one command. It is the best option if you can spare the puller some local disk.
$ rclone sync mc:/ /srv/stage/mc --filter-from minecraft.filter$ restic -r s3:https://s3.example.com/game-backups/restic backup /srv/stage/mc --tag mcrestic reads AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and RESTIC_PASSWORD (or RESTIC_PASSWORD_FILE) from the environment. Lose the restic password and the repository is unreadable - by design. restic backups to S3 covers initialising the repository and the rest.
Retention and cleanup#
Storage without lifecycle rules does not delete anything on its own, so retention is part of your job script.
The obvious command is the wrong one. rclone delete --min-age 14d filters on each object's modification time, and rclone preserves the source file's modification time when it uploads (it stores it in the object's metadata). A config file nobody has touched for a month arrives in tonight's dated folder already "a month old", and --min-age 14d deletes it the moment the job finishes. Your newest backup quietly loses every file that had not changed recently - exactly the files you would not think to check.
Delete whole dated prefixes by their name instead. The folder name is the date the copy was taken, which is what you mean by age:
CUTOFF=$(date -u -d '14 days ago' +%F)rclone lsf --dirs-only store:game-backups/mc/daily | while read -r d; do d=${d%/} if [[ "$d" < "$CUTOFF" ]]; then rclone purge "store:game-backups/mc/daily/$d" fidoneISO dates (2026-10-08) sort the same way as text and as time, which is why the plain string comparison works. date -d is GNU date, standard on Linux; on macOS use date -u -v-14d +%F. The same applies to the --backup-dir layout: prune the dated changed/ folders by name, never with --min-age. For restic, retention is a policy:
$ restic -r s3:https://s3.example.com/game-backups/restic forget \ --tag mc --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --pruneA sensible policy for most game servers is a week of dailies, a month of weeklies, and a copy before every major update kept indefinitely. Size the bucket from that: a 2 GB Minecraft world with dated full copies for fourteen days needs about 28 GB; the same history in restic is usually a small multiple of one world. How much storage a game server needs helps with the world side of that sum.
Scheduling the job#
Put the whole thing in one script so the schedule is one line:
#!/usr/bin/env bashset -euo pipefailDAY=$(date -u +%F)CUTOFF=$(date -u -d '14 days ago' +%F)rclone copy mc:/ "store:game-backups/mc/daily/$DAY" \ --filter-from /etc/rclone/minecraft.filter --log-file /var/log/mc-backup.logrclone lsf --dirs-only store:game-backups/mc/daily | while read -r d; do d=${d%/} if [[ "$d" < "$CUTOFF" ]]; then rclone purge "store:game-backups/mc/daily/$d"; fidonecurl -fsS -m 10 https://hc.example.com/ping/mc-backup > /dev/null || trueThen crontab -e and 0 4 * * * /usr/local/bin/mc-backup.sh. set -euo pipefail stops the script at the first failure, so a failed copy never goes on to delete old backups. The last line pings a dead-man's-switch monitor (Healthchecks.io and similar services), which alerts you when the ping does not arrive - the only reliable way to notice a backup job that silently stopped. On a Windows puller, Task Scheduler runs the same rclone commands from a .bat file; rclone behaves identically there.
Restoring from the bucket#
A backup nobody has restored is a hypothesis. Restore one before you need to:
- Pick a day and download it to your PC:
rclone copy store:game-backups/mc/daily/2026-10-07 ./restore-test. - Open the world in a local copy of the game, or on a test server, and walk around the main base.
- For a real restore, stop the game server, move the damaged world folder aside, upload the restored one with rclone or the file manager, and start the server.
Pushing the restore straight back over SFTP works the same way in reverse - rclone copy store:game-backups/mc/daily/2026-10-07 mc:/ - but only with the server stopped, or the game's next save overwrites what you just put back. Testing a restore before you need it turns this into a quarterly habit.
FAQ#
Can the game server push to S3 by itself?
Not from a panel game server: its scheduler runs console commands, backups and power actions, not shell scripts. Some games have plugins that upload backups to S3, and those work if you trust the plugin. Otherwise pull from outside with rclone, as above.
How often should I copy the world off-site?
Daily is right for most servers, timed for the quietest hour. Add a manual copy before every game update and every major plugin change. Hourly copies of a large world cost more than they protect.
Is the panel's backup not enough?
It is enough for most mistakes, and it is the fastest restore. It does not survive the server being deleted, and slots rotate. The S3 copy exists for the cases panel backups cannot cover.
Should I encrypt game world backups?
restic encrypts everything by default. With rclone you can wrap the storage remote in a crypt remote. For a game world the main reason is that configs often contain RCON and database passwords.
Will copying the world slow the server down?
Reading a few hundred megabytes over SFTP is light, but a big world on a busy server can cause a brief stutter. Run the job at the quietest hour and use --bwlimit in rclone if players notice.




Comments
Completely anonymous: no account, no email, no cookie. We store the name you type, the text and the time - nothing else. Links are limited and markup is not rendered.