Backups and restore
The database is encrypted at rest and the key is not recoverable. A backup without its key is noise. Backups copy .env.server and data/.db-key when those files exist. A key supplied only through the process environment is not automatically written into the archive: keep that matching key separately. Treat archives as private because their database and configuration can contain secrets.
From the admin panel
Admin, Server settings, Backup: create an archive, verify one, download it, delete it, or restore from it. Archives land in ODM_BACKUP_DIR (default ~/odm-backups). A world hosted from the apps uses Move your world in App settings instead of this Backup section.
Move your world
In the desktop or Android app, open Settings, Your world on this computer/device, Move your world. Export world saves the whole device world as an odm-world-*.tar.gz file: accounts, campaigns, characters, prep, installed world packs, pictures and cached narration. Keep the app open until it finishes.
On the destination device, leave any table first and choose Import world. The app checks the file, previews its contents and asks before Replace my world. Import replaces the destination world and restarts its server; the previous world stays set aside until the next import. The owner is signed in after the swap. Provider keys and sign-ins are excluded: enter your AI key again in Story AI and let friends sign in again. The exported campaigns are readable by anyone holding the file, so keep it private.
This is the portable device-world format, separate from a self-hosted server's backup archive. Addon records travel, but addon packages need reinstalling on a supported destination.
From the command line
node scripts/odm-backup.mjs # to ~/odm-backups
node scripts/odm-backup.mjs /path/to/backups
node scripts/odm-restore.mjs odm-backup-<stamp>.tar.gz /tmp/odm-restore-check # dry run
node scripts/odm-restore.mjs odm-backup-<stamp>.tar.gz --liveUnder Docker, run each through ./scripts/docker-entrypoint.sh inside the container so the key is loaded. Stop the app before a command-line backup; the live restore refuses to run while the server is listening.
What a backup does
- Opens the encrypted database with the key to prove it is readable, and checkpoints the write-ahead log.
- Stages the persistent state:
data/(the database, world packs, the Docker key file), uploaded and generated media, files undermodels/, and.env.serverwhen present. The defaultdata/addons/folder is included; addon files under a custom directory outside the managed paths need a separate copy. The admin backup can omit downloadable files undermodels/unless you choose to include them. - Writes a manifest and a timestamped
odm-backup-<stamp>.tar.gz, and prints its SHA-256 (archives over 2 GiB are hashed as a stream).
What a restore does
A restore checks archive paths, extracts to a temporary folder, opens the database, runs an integrity check and reports its campaign, user and message counts. The command-line restore requires the matching key inside the archive's .env.server or data/.db-key. The admin restore can fall back to the current server's key when the archive has none; verification on that server therefore does not prove the archive contains its own key.
For a portable command-line backup, make sure one of those files contains the actual key before taking the backup. Keep the original value separately as well when your deployment supplies it only through the process environment.
The command-line dry run stops after verification. --live stages the replacement, swaps managed paths by rename and retains the previous state; a failed swap rolls back. It refuses while the app is listening. Check the output for the retained paths before removing any previous copy.
Manual copies
If you would rather copy files: both data/local-roleplay.sqlite and its key are required, plus public/uploads/; add data/worlds/ if packs were installed. public/generated* is optional (pictures and audio can be regenerated). Under Docker the odm-data, odm-uploads, odm-generated and odm-audio volumes are the same set.
Per-item exports
- A character as
.odm-character.json, portrait inside. - A workshop as
.odm-workshop.json, pictures inside. - A campaign's story as HTML, ODT or DOCX: a reading copy, not a save.
Character and workshop files import on other servers; story documents are reading copies. Play state (the chronicle, the seats, the live sheets) moves only with the database.
When to back up
Before every update, and after a session you would mind losing. The apps' Move your world export works on phones too. Export before switching between APK and Play installs, since uninstalling deletes the private world.