← All guidesGame Server Operations

Back Up a Minecraft Server to DigitalOcean Spaces

Create consistent, encrypted-in-transit Minecraft backups, upload them to a private DigitalOcean Spaces bucket, and prove you can restore one.

Decide what a successful backup means before you automate it

A backup is only useful if it restores the world your players expect. For a typical Java server, that usually means the world directories, configuration, whitelist, operators list, plugins or mods, and the server version or container definition needed to run them. Write down where those live before you write a script; many hosts place the world outside the directory that contains server.jar.

This guide targets a Linux-hosted Java server and uses the AWS CLI because Spaces accepts S3-compatible requests. It does not make a live copy of a database or replace a tested disaster-recovery plan. If your server uses a panel, Docker volume, or a modpack with its own data directories, add those paths deliberately and test the result on a separate machine or directory.

  • A private Spaces bucket in a region you have chosen intentionally.
  • A limited Spaces access key with Read/Write/Delete access to that one backup bucket.
  • The AWS CLI, tar, and enough local disk space to create one archive.
  • A way to run console commands as the Minecraft server: RCON, a panel console, or a wrapper script.

Create a private bucket and a key just for the backup job

Create a bucket such as minecraft-backups-your-server in Spaces Object Storage. Pick the region carefully: the bucket name is unique within that region, and the regional endpoint is part of every CLI command. Do not enable public file listing or use the CDN for backups.

In the Spaces Access Keys tab, create a limited key for this bucket only, with Read/Write/Delete permission. Save the secret when it is shown; the control panel displays it only once. A separate key lets you rotate or revoke the backup job without disturbing another application. Limited keys and S3 bucket policies cannot be used together, so do not add a bucket policy to this simple setup.

Store credentials outside the backup script
sudo install -d -m 700 /etc/minecraft-backup
sudo nano /etc/minecraft-backup/spaces.env
# Add these two lines, then save:
# AWS_ACCESS_KEY_ID=your_spaces_key
# AWS_SECRET_ACCESS_KEY=your_spaces_secret
sudo chmod 600 /etc/minecraft-backup/spaces.env

Enable versioning before the first upload

Versioning is an extra recovery layer, not a substitute for retention. With it enabled, an overwrite or ordinary delete creates history you can inspect and restore. DigitalOcean requires the regional endpoint here: use nyc3.digitaloceanspaces.com, for example, not the bucket origin endpoint that includes your bucket name.

Set AWS_DEFAULT_REGION to us-east-1 for the AWS CLI’s required client-side setting; the Spaces endpoint, not that value, selects the actual bucket region. Replace the placeholders below with your bucket and Spaces region.

Enable and verify Spaces versioning
set -a
. /etc/minecraft-backup/spaces.env
set +a
export AWS_DEFAULT_REGION=us-east-1
aws s3api put-bucket-versioning --bucket YOUR_BUCKET --endpoint-url https://YOUR_REGION.digitaloceanspaces.com --versioning-configuration Status=Enabled
aws s3api get-bucket-versioning --bucket YOUR_BUCKET --endpoint-url https://YOUR_REGION.digitaloceanspaces.com

Archive a consistent world, then upload it

Do not tar a world while the server is writing chunks. The script below uses RCON to run save-off, save-all flush, and save-on around the archive. Replace the RCON command with the console mechanism for your server. If you cannot reliably pause saves, stop the service before archiving and start it again afterwards; a few minutes of downtime is safer than a backup that only sometimes restores.

Adjust SERVER_DIR and the include list to match your installation. The example keeps common Paper or vanilla files and excludes logs, cache, and an existing backups directory. It produces a dated archive, uploads it under a predictable prefix, and retains the local archive only until the upload succeeds.

/usr/local/sbin/backup-minecraft-to-spaces
#!/usr/bin/env bash
set -euo pipefail

SERVER_DIR=/srv/minecraft
BACKUP_DIR=/var/backups/minecraft
BUCKET=YOUR_BUCKET
REGION=YOUR_REGION
PREFIX=java-server
RCON='/usr/local/bin/rcon-cli --host 127.0.0.1 --port 25575 --password-file /etc/minecraft-backup/rcon-password'

set -a
. /etc/minecraft-backup/spaces.env
set +a
export AWS_DEFAULT_REGION=us-east-1
mkdir -p "$BACKUP_DIR"
STAMP=$(date -u +%Y-%m-%dT%H-%M-%SZ)
ARCHIVE="$BACKUP_DIR/minecraft-$STAMP.tar.gz"

$RCON save-off
trap '$RCON save-on' EXIT
$RCON save-all flush
tar -C "$SERVER_DIR" -czf "$ARCHIVE" \
  --exclude=logs --exclude=cache --exclude=backups \
  world world_nether world_the_end server.properties whitelist.json ops.json plugins mods config
$RCON save-on
trap - EXIT

aws s3 cp "$ARCHIVE" "s3://$BUCKET/$PREFIX/$(basename "$ARCHIVE")" \
  --endpoint-url "https://$REGION.digitaloceanspaces.com" --only-show-errors
rm -f "$ARCHIVE"

Schedule it and give failures somewhere to go

Run the script as the account that can read the server files and use the console. Start with a manual run, watch it finish, and confirm that the object appears in the intended bucket and prefix. Then schedule it. A timer is preferable to an unattended command you never inspect: at minimum, route stderr to a log and arrange an alert when the command exits nonzero.

A daily backup is a reasonable starting point for a quiet personal server, but it is not a universal answer. Choose frequency from your acceptable data loss. If losing an evening of building is unacceptable, back up more often and balance that against archive size, upload time, and retention cost.

Run every day at 04:17 UTC
17 4 * * * minecraft /usr/local/sbin/backup-minecraft-to-spaces >> /var/log/minecraft-backup.log 2>&1

Apply retention without deleting your only recovery point

Spaces lifecycle rules can expire objects after a chosen number of days and remove incomplete multipart uploads. Set a period that matches your recovery needs, then confirm what it covers before turning it on. A simple 30-day rule is easy to explain, but it may be too short for a world where damage is noticed weeks later.

Versioning changes the deletion story: deleting an object can leave prior versions and delete markers. Review versioning and lifecycle behavior together, especially before relying on automatic cleanup. Keep at least one independently tested recovery path for a world you cannot afford to lose.

Example: expire backup objects after 30 days
s3cmd expire --expiry-days=30 --expiry-prefix= s3://YOUR_BUCKET

Prove a restore works before the emergency

Pick a recent archive and restore it into an empty test directory. Check that the archive contains the expected world and configuration files before you point a Minecraft process at it. For a stronger test, start an isolated copy on a different port with the same server version and let an administrator join it.

Do not restore over the production directory while the production server is running. Stop the server, keep the damaged directory until the restored world has been verified, and then swap directories in a planned maintenance window.

Download and inspect one backup
mkdir -p /tmp/minecraft-restore-test
aws s3 cp s3://YOUR_BUCKET/java-server/minecraft-YYYY-MM-DDTHH-MM-SSZ.tar.gz /tmp/minecraft-restore-test/ --endpoint-url https://YOUR_REGION.digitaloceanspaces.com
tar -tzf /tmp/minecraft-restore-test/minecraft-YYYY-MM-DDTHH-MM-SSZ.tar.gz | head -40
tar -xzf /tmp/minecraft-restore-test/minecraft-YYYY-MM-DDTHH-MM-SSZ.tar.gz -C /tmp/minecraft-restore-test