Running a server

Backups

On this page

The server backs up the world, its own files and plugin data during play, without stopping anybody and without pausing the game. Scheduled backups are off by default, because they need disk space somebody has thought about. backup now works either way.

Turning it on

In rustmc.yml:

backups:
  enabled: true

That takes a backup every six hours into backups/ in the server's folder. Point backups.directory at another drive if you can: a backup on the same drive does not survive that drive failing.

Scheduled backups do not run on a server started read-only.

Settings

Under backups: in rustmc.yml:

KeyDefaultMeaning
backups.enabledfalseTakes a backup every interval-minutes, during play
backups.directorybackupsWhere backups go: relative to the server's folder, or absolute
backups.interval-minutes360Minutes between scheduled backups, from 5 to 10080
backups.keep-recent4How many of the newest backups are always kept
backups.keep-daily7How many days keep their newest backup
backups.keep-weekly4How many weeks keep their newest backup
backups.max-total-gib0The most all backups together may take, in GiB. The oldest go first. 0 is no cap
backups.min-free-gib10The space, in GiB, a backup must leave free on its drive and on the world's
backups.max-mib-per-second50The most a backup reads, in MiB a second. 0 is no limit
backups.compression-level1The gzip level, 0 to 9. Region files are already compressed, so higher levels cost much and win little
backups.only-after-playtrueSkips a scheduled backup when nobody has been online since the last one

The day and week tiers count days and weeks that have a backup, so a server left off for a month keeps its old ones. The newest backup, and the one just written, are never deleted, whatever these say. Old backups are removed only right after a new one has been written and checked. Only files named like a backup (backup-<date>-<time>-<reason>.tar.gz) are ever deleted; anything else in the folder is left alone.

The schedule

The schedule looks every minute. When the next backup is due comes from the newest backup in the folder, and whether anybody has played since from a marker file beside them, so a server restarted more often than the interval still gets its backups. The first backup, when there is none yet, runs whether or not anybody has played.

Commands

CommandDoes
backupSays whether scheduled backups are on, whether one is running, the last one with its notes, and the last failure
backup nowTakes one now, in the background. It works whether or not backups.enabled is on
backup listLists the newest ten, with their sizes, how many notes each has and the first of them

Only one backup runs at a time: backup now while one is running says so and starts nothing. The command works at the console, over RCON and in game, and is always available.

NodeDefaultCovers
minecraft.command.backuplevel 3The command
backup.notifylevel 3Being told in game when a backup fails

What is in a backup

  • The whole world: every dimension and all player data.
  • The server's top-level .json, .properties, .yml, .yaml and .txt files.
  • Everything in plugins/ except code (.wasm, .dll, .so, .dylib, .exe, .jar, .bat, .cmd, .sh).
  • The plugin SQLite database, copied whole and consistent, wherever storage.json puts it.

Left out: logs, the server's other folders, temporary files, and .packets files, which the server makes again.

MySQL is not included. If any plugin stores rows in MySQL, the console says so and the backup's notes say so too. Back that database up with mysqldump.

How it stays consistent

A backup first runs an ordinary full save. Then it copies everything but the region files, at background priority, with saves still going. Then it holds off further saves for a moment: it hard links the region files, which the server only ever replaces whole and so stay as they were, and copies again whatever changed, for at most five seconds. After that it compresses at its leisure, on one thread at background priority, under the read limit. While saves are held, an autosave skips its round and /save-all says so. The game's tick never waits for any of this.

On a drive without hard links, region files are copied in the first step too, and the console says so. The moment stays short, but a region still changing when the five seconds run out fails that backup. While saves are held nothing over 16 MiB is read: a file that large is judged by its size and time, and if it changed it keeps the copy from just before, with a note. Without hard links, a region that large which changed in the meantime fails that backup. Any other file that changes during the moment keeps the copy from just before. One that never holds still is kept with a note.

If saving is off (/save-off), no save comes first and the backup takes the files as they stand, with a note.

A backup with notes is not a clean one. Notes say what did not go to plan, such as a file that may have been copied mid-write. The console shows every note, the line that ends a backup counts them, backup shows the last backup's, and backup list shows the first of each. All of them are in the archive's backup.json, and in a .notes file beside the archive, which any text editor opens.

The game keeps running during the save. So a backup is as consistent as one save: it is exactly one completed save, never parts of two, but a save takes a moment, and an item moved during it can be in a chest and in a pocket, just as after a crash. Plugins that hold data in memory between their own saves are as of their last save.

Each archive is written under a .partial name, read back with every file's SHA-256 checked, and only then given its final name. So a backup-*.tar.gz is one that has been proved readable. A .partial file is never a backup, and the next start removes it.

When the disk is short

Before starting, a backup works out what it needs from the last archive's size (or, for the first, the size of everything it will copy). If that would leave less than min-free-gib free, it stops and deletes nothing: old backups go only after a new one has been read back, so a failed backup never costs you an older one. That means there must be room for one more backup than you keep. Delete old ones by hand, or lower the keep settings, if it reports it cannot fit. It checks both drives again as it writes, and if either falls short it deletes what it wrote and stops.

Whenever a backup fails, the console says why, holders of backup.notify (and whoever ran backup now) are told in game, and backup shows it until one works.

Restoring

  1. Stop the server. Nothing detects a running server: a restore beside one will be overwritten by its next save.

  2. Pick an archive from backups/, and copy it elsewhere if you may want it again.

  3. Run the same command you start the server with, adding --restore and the archive:

    rustmc-server --restore backups/backup-20261031-183500-auto.tar.gz
    

    If you start the server with an address and a world path, give those too:

    rustmc-server --restore D:\saves\backup-20261031-183500-auto.tar.gz 0.0.0.0:25565 D:\worlds\exalted
    
  4. Start the server as usual.

The restore unpacks and checks every file in the archive first. If anything is wrong it says so and changes nothing. An archive holding code, or anything else a backup never holds, is refused, and so is one with no world.

Then it moves what was there to <world>.before-restore-<time> and puts the backup in its place: the world and plugin data. Delete the before-restore folder when you are happy, since it takes as much room as your world.

Some things stay as they are now:

  • Installed plugin code, so plugins you added since the backup are still there.
  • rustmc.yml, server.properties and plugins/storage.json. How the server is set up is not part of what a restore rolls back, and an archive does not get to choose its passwords or database. They are in the archive under server/ if you want an old setting back: copy it by hand.
  • ops.json, whitelist.json, banned-players.json and banned-ips.json, because a restore to undo damage should not bring back an operator you removed, or lift a ban. Add --restore-access to take the backup's. Either way the restore prints which of them differ from the backup, so you can decide.

If a step fails, the restore undoes what it did and says so. If the machine stops part way, the server refuses to start. The restore may already be complete, so look at the world first: if it is whole, delete <world>.restoring. If not, put back the old data from <world>.before-restore-<time>, then delete <world>.restoring. A <world>.restoring left from before anything changed just needs deleting, or another --restore.

Without the server

A backup is a plain gzipped tar, so any tool opens one:

tar -xzf backup-20261031-183500-auto.tar.gz

world/ is the world and server/ the server's files. On a server started with a world path, the server's files are kept in the world's folder, so there is no server/ and everything is in world/. The plugin SQLite database is a single file, already complete.

Security and privacy

A backup holds what the server folder holds, including any password in storage.json, rustmc.yml or server.properties (the RCON password, the management secret). Keep backups as private as the server itself. On Linux and macOS the archives are readable only by the server's user, and the backup folder is closed to others. Windows gives them the folder's ordinary permissions.

From docs/backups.md in the RustMC repository at bbd81209ad.