Terraria Field guide

Back up and restore a Terraria world without overwriting the only copy

Back up Terraria world and configuration, keep an off-host copy and verify restoration in a separate instance.

Back up and restore a Terraria world without overwriting the only copy

A usable Terraria backup must load as the intended world, not merely appear in an archive listing. Stop the writer, preserve the world and its configuration, copy the archive outside the VPS and rehearse recovery into a fresh directory.

This procedure covers vanilla PC Terraria on Ubuntu 24.04. It follows our tmux-based installation: account terraria, home /srv/terraria, worlds under /srv/terraria/worlds, and example release /opt/terraria-release/1458/Linux. Adjust the selected filename if your world is not Coop.wld. It does not restore tModLoader data, TShock state or console/mobile saves.

Decide what recovery must preserve#

Copy the entire configured worlds directory, including any rolling copies, and /srv/terraria/serverconfig.txt. Record the actual launch command and exact release. If you use a banlist or additional launch configuration outside those paths, export that actual file separately; the default banlist can be relative to the executable's working directory.

The official server archive documents world selection and rolling-backup configuration. Rolling copies beside the active world still share its disk. They are useful recovery candidates, not protection against losing the VPS.

Player inventories belong to separate character saves. Ask players to protect their own characters. Restoring an older world beside newer characters can also put carried items and world containers at different points in time; agree on a recovery point before the group rejoins.

Save, stop and create a closed snapshot#

Attach to the existing console:

bash
sudo -iu terraria tmux attach-session -t terraria

Enter save, wait for completion, then exit. Wait for the process to return to its shell. Keep automatic launchers stopped. A generic process kill is not evidence that the latest changes were written.

In a shell owned by terraria, run:

bash
(
  set -eu
  umask 077
  cd /srv/terraria
  test -d worlds
  test ! -L worlds
  test -f serverconfig.txt
  test ! -L serverconfig.txt
  test -z "$(find worlds -type l -print -quit)"
  terraria_backup_dir=$(mktemp -d /srv/terraria/backups/snapshot.XXXXXX)
  tar -czf "$terraria_backup_dir/terraria.tar.gz" worlds serverconfig.txt
  sha256sum "$terraria_backup_dir/terraria.tar.gz"
  tar -tzf "$terraria_backup_dir/terraria.tar.gz"
)

The backups directory must already exist and belong to terraria, as in the setup guide. Retain the printed exact archive path and checksum. The symlink check prevents this snapshot from silently depending on world data elsewhere. If it fails, resolve the actual data layout before archiving.

Keep a verified copy outside the server#

Archive integrity and successful world recovery are separate checks.

Use the setup guide's private export steps to stage an owner-only archive for your SSH account, then download it from your workstation. Compare its SHA-256 with the source. Store the checksum and selected release beside the off-host copy. The configuration contains the server password, so keep this archive private.

Choose retention based on acceptable lost progress: keep several distinct recovery points and a pre-update copy. An automatic job must coordinate save/stop and restart; simply placing the tar command in cron does not recreate this stopped snapshot. Check that failed uploads do not delete the last working off-host copy.

Extract a rehearsal copy under an unprivileged account#

Use your own verified archive, available to terraria, and enter that exact path when prompted. Run the following as terraria. It refuses links, special files, unexpected top-level paths and duplicate archive members, then extracts into a new directory without touching the active world:

Before this rehearsal, select a retained server executable and PC client compatible with the snapshot’s recorded release. The command below uses 1.4.5.8 as the example: replace /opt/terraria-release/1458/Linux when your verified archive requires another release. Do not test a newer world with an older runtime or treat a version rejection as file corruption.

bash
(
  set -eu
  umask 077
  read -r -p "Verified archive path: " terraria_archive
  test -f "$terraria_archive"
  test ! -L "$terraria_archive"
  terraria_restore=$(mktemp -d /srv/terraria/restore-check.XXXXXX)
  python3 - "$terraria_archive" "$terraria_restore" <<'PY'
import pathlib
import sys
import tarfile

with tarfile.open(sys.argv[1], "r:gz") as archive:
    seen = set()
    for member in archive.getmembers():
        name = pathlib.PurePosixPath(member.name)
        if name.is_absolute() or ".." in name.parts or not name.parts:
            raise SystemExit("Unsafe archive path")
        if not (member.isdir() or member.isfile()) or str(name) in seen:
            raise SystemExit("Unsupported or duplicate archive member")
        if name.parts[0] not in {"worlds", "serverconfig.txt"}:
            raise SystemExit("Unexpected archive member")
        if name.parts[0] == "serverconfig.txt" and not (
            len(name.parts) == 1 and member.isfile()
        ):
            raise SystemExit("Unexpected configuration member")
        seen.add(str(name))
    archive.extractall(sys.argv[2], filter="data")
PY
  test -s "$terraria_restore/worlds/Coop.wld"
  printf 'world=%s/worlds/Coop.wld\nworldpath=%s/worlds\nbanlist=%s/banlist.txt\nport=17777\nupnp=0\n' \
    "$terraria_restore" "$terraria_restore" "$terraria_restore" > "$terraria_restore/restore.ini"
  printf 'Restore directory: %s\n' "$terraria_restore"
  cd /opt/terraria-release/1458/Linux
  ./TerrariaServer -config "$terraria_restore/restore.ini" -ip 127.0.0.1
)

This uses Ubuntu 24.04's Python 3.12 extraction filter. The rehearsal configuration deliberately selects the copied world, omits autocreate and binds a different port to loopback. The archived production configuration remains intact for inspection. Before launching, check for a listener on the test port with ss -ltn. An empty result does not reserve the port; if startup reports a conflict, select another port rather than testing an unidentified running instance. If port 17777 is occupied, choose another free port in both the configuration and tunnel; do not displace its owner.

Verify recovery before promoting it#

Keep the rehearsal in a terraria tmux session if needed. From a separate workstation terminal, establish a tunnel:

bash
ssh -N -L 17777:127.0.0.1:17777 YOUR_SSH_USER@YOUR_VPS_IP

A matching PC client can then join 127.0.0.1, port 17777. Inspect a known recent landmark and world contents, make a disposable change, save, exit and reload the same rehearsal copy. Only that sequence checks that the recovered world is usable and writable.

For real recovery, stop both instances and retain the damaged/current world separately. Copy the verified recovery candidate to a fresh production filename under terraria:terraria, point world= at it, preserve required password settings and disable autocreate. Follow the explicit-selector steps in the transfer guide. Do not replace the active file while either process writes it.

If a rolling .bak is the candidate, copy it under a fresh .wld filename for the same isolated test. A historical failed-world thread shows why the adjacent backup can fail too. Preserve originals; renaming an extension does not repair corrupt bytes. If no retained version loads, stop further writes and preserve the complete set for investigation.