Nimbusv1.0.0

Backup Module

Configure scheduled tar+zstd snapshots, retention (GFS), scope, excludes, compression, and quiesce behaviour for the Backup module.

The Backup module owns a single TOML file at config/modules/backup/backup.toml. It is auto-generated with defaults on module install. Edits can be made by hand (picked up on the next scheduler tick + reload) or atomically via PUT /api/backups/config — both paths validate and hot-reload the scheduler.

Complete Example

config/modules/backup/backup.toml
[backup]
enabled = true
local_destination = "data/backups"
max_concurrent = 2
compression_level = 3
# 0 = auto (Runtime.availableProcessors() / 2, min 1). zstd-jni runs native
# multi-threaded compression when workers > 0 — this is the 3-5x speedup
# over subprocess `tar --zstd`.
compression_workers = 0
quiesce_services = true
quiesce_wait_seconds = 2

[backup.scope]
services = true
dedicated = true
templates = true
controller_config = true
state_sync = true
database = true

[backup.excludes]
patterns = [
  "logs/**", "crash-reports/**", "*.log", "*.log.gz",
  "cache/**", "tmp/**", "*.lock", "session.lock",
  "*/region/*.mca.tmp", "config/bStats/**", "plugins/bStats/**"
]

[[backup.schedules]]
name = "hourly"
cron = "0 * * * *"
retention_class = "hourly"
targets = ["services", "dedicated", "database"]

[[backup.schedules]]
name = "daily"
cron = "0 3 * * *"
retention_class = "daily"
targets = ["all"]

[[backup.schedules]]
name = "weekly"
cron = "0 4 * * 0"
retention_class = "weekly"
targets = ["all"]

[backup.retention]
hourly_keep = 24
daily_keep = 7
weekly_keep = 4
monthly_keep = 3
keep_manual = true
# Age in days after which FAILED rows are deleted. 0 = keep forever.
failed_keep_days = 7

[backup]

Top-level module switches and per-job defaults.

KeyTypeDefaultDescription
enabledBooleantrueMaster switch. When false, scheduled jobs do not run and manual triggers return MODULE_DISABLED. Config editing is still allowed.
local_destinationString"data/backups"Directory that receives .tar.zst archives. Relative paths are resolved against the Nimbus root. Created if missing.
max_concurrentInt2Max backups running at the same time (enforced by a semaphore). Must be 1..32. Higher values only help if I/O is not the bottleneck.
compression_levelInt3zstd level. Must be 1..22. Levels above ~9 have rapidly diminishing returns; 3 is the sweet spot for live server data.
compression_workersInt0zstd-jni worker thread count. Must be 0..64. 0 = auto (Runtime.availableProcessors() / 2, min 1). Any > 0 value enables zstd-jni's native multi-threaded mode.
quiesce_servicesBooleantrueBefore archiving a service directory, send save-off + save-all flush to force a clean on-disk state, then save-on to resume autosave. Skipped for stopped services.
quiesce_wait_secondsInt2Seconds to wait after save-all flush before archiving. Must be 0..60. Give large worlds more time (5–10s) if region files are still being written when tar starts.

[backup.scope]

Master on/off switches per target class. A target still needs to appear in a schedule's targets to actually be archived — these keys just gate which classes are considered at all.

KeyTypeDefaultDescription
servicesBooleantrueRunning + stopped group services under paths.services.
dedicatedBooleantrueDedicated services under paths.dedicated.
templatesBooleantrueServer templates under paths.templates.
controller_configBooleantrueThe controller's own config/ tree (nimbus.toml, group configs, module configs).
state_syncBooleantrueCanonical state-sync data under services/state/. Independent of running services.
databaseBooleantrueDatabase dump. SQLite uses VACUUM INTO; MySQL / PostgreSQL shell out to mysqldump / pg_dump. Missing clients are logged as PARTIAL.

[backup.excludes]

KeyTypeDefaultDescription
patternsList<String>see example aboveGlob patterns (rsync-style). Any path matching any pattern is skipped during archiving.

Defaults strip log files, crash reports, lock files, partial region writes, and bStats telemetry.


[[backup.schedules]]

Zero or more schedules. Each is a cron trigger with its own retention class and target set.

KeyTypeDefaultDescription
nameStringrequiredUnique schedule name (A-Z a-z 0-9 _ -).
cronStringrequired5-field POSIX cron (min hour dom mon dow). Evaluated by a hand-rolled parser; ranges (0-30), steps (*/5, 0-30/5), and comma lists are supported.
retention_classStringrequiredOne of hourly, daily, weekly, monthly, manual. Drives which retention counter (hourly_keep, ...) applies to archives produced by this schedule.
targetsList<String>requiredTarget names to back up in this run (see below). Must be non-empty.

Allowed target values

TokenArchives
allEvery scope enabled in [backup.scope]
servicesAll group services
dedicatedAll dedicated services
templatesAll templates
config, controller_configController config tree
databaseDatabase dump
state, state_syncState-sync canonical data

Services placed on remote agent nodes are currently skipped with PARTIAL status — cluster-node archive streaming is on the roadmap. Local services and canonical state-sync are unaffected.


[backup.retention]

GFS (Grandfather-Father-Son) retention. Counters are applied per (targetType, targetName, retention_class) tuple, so every service, every dedicated service, and every template is pruned independently.

KeyTypeDefaultDescription
hourly_keepInt24Archives to keep for retention_class = "hourly". Must be >= 0.
daily_keepInt7Archives to keep for retention_class = "daily".
weekly_keepInt4Archives to keep for retention_class = "weekly".
monthly_keepInt3Archives to keep for retention_class = "monthly".
keep_manualBooleantrueWhen true, manual backups (triggered via backup run or POST /api/backups) are never pruned.
failed_keep_daysInt7Age in days after which FAILED rows are deleted. FAILED rows do not count against per-class keep budgets, so a chronically failing target would otherwise accumulate rows forever. 0 = keep forever (not recommended).

Validation Rules

Invalid values cause a 400 Bad Request from PUT /api/backups/config (editor) and prevent hot-reload; the previous in-memory config stays active.

  • compression_level in 1..22
  • compression_workers in 0..64
  • max_concurrent in 1..32
  • quiesce_wait_seconds in 0..60
  • All *_keep counters >= 0, failed_keep_days >= 0
  • Schedule names unique, non-blank, match [A-Za-z0-9_-]+
  • Schedule retention_class in the five allowed values
  • Schedule cron must parse
  • Schedule targets non-empty, every token in the allowed target list

Archive Layout

Every archive is a .tar.zst with a single trailing entry MANIFEST.sha256 — one line per file:

MANIFEST.sha256
3a9d0e02b6b1...  world/level.dat
bb7f6c4d2915...  world/region/r.0.0.mca

backup verify <id> streams the archive once, recomputes every entry's SHA-256, and compares against the manifest. Tampering or truncation is detected without unpacking.


  • Backup Guide — operational workflow, restore, verify, prune
  • Backup Module Internals — archiver pipeline, SHA-256, cron evaluator
  • GET /api/backups, PUT /api/backups/config, POST /api/backups, POST /api/backups/{id}/verify — see API Reference