Updates And Backups
Back up before every update, keep your settings in the private config, and keep your code changes in your own repository. Migrations only move forward.
Versions
health.php and Control Panel > Diagnostics report several separate versions. Never treat one as another:
| Name | Current | Set in |
|---|---|---|
| Server release | 0.1.0 | lib/version.php (SERVER_VERSION) |
| Client release | 0.1.0 | ExampleMod CMakeLists.txt (project(... VERSION)) |
| Protocol | 1 | Both PROTOCOL.md files and both sides' code |
| Baseline | baseline-1 | A template feature-set label, not a release |
| Schema | 007_connector_calls | sql/ files and SCHEMA_MIGRATIONS in lib/app.php |
Bump the protocol only for a change a version-1 peer would misread, and then in both repositories together.
Backups Versus Checkpoints
| Kind | Contains | Where |
|---|---|---|
Full backup: sudo bash scripts/backup.sh | The whole database and config/config.php | /home/dwemer/example-ai-server-backups/<time>/, outside the web root |
| Dashboard backup: Control Panel > Backups | The database only, no config | backup_dir from the config, or a temporary folder that may be emptied on restart |
| Session checkpoint: Roleplay > Checkpoints | One session's conversation lines and memory notes | Inside the same database |
A checkpoint is not a backup: it is lost with the database. Backup folders contain your token and keys; keep them private and out of Git. Checkpoints are covered in Data and Memory.
Update A Manual Install
In WSL:
cd /var/www/html/ExampleServer
git rev-parse HEAD
sudo bash scripts/backup.sh
sudo bash scripts/update.sh
Write down the commit that git rev-parse HEAD prints and the backup folder. Together they are the matching code and data to return to.
update.shrefuses tracked local edits, backs up the database and config, fast-forwards only, then migrates.- It stops if your branch has no upstream or has diverged; merge by hand.
- It stops if the update would start tracking a file you have privately, such as
config/config.php. - It never resets, cleans or deletes anything, and never restores anything itself.
A manual install follows the branch it was cloned from, main or dev. A launcher install is updated with the launcher's Update and Switch commands; see the launcher route.
DwemerDistro updates and the custom mods port. Update Distro keeps your CUSTOM_MODS_PORT and other service ports, so your custom mod addresses stay the same. If you change the port, run sudo ddistro_custom_mod setup-web and pair every client again. See Ports and branches.
Migrations
scripts/migrate.php(run byinstall.shandupdate.sh) applies missing migrations in order, one transaction per file. A second run applies nothing.- If one fails, that file is rolled back, earlier ones stay and the code is already updated.
update.shexits3and prints the backup folder. Prefer fixing forward: fix the cause and runsudo -u dwemer php scripts/migrate.phpagain. - There are no down migrations. To go back to before the update, return code and data together:
- Stop the client.
- Check out the commit you recorded without resetting or cleaning, for example
git switch --detach <commit>. This keepsconfig/config.php, backups and other untracked files. Commit or copy your own local edits first. - Restore the database from the backup made with that update, as in Restore a backup, and the config from it if needed.
503 not_migratedfor the missing migrations, and older code on the newer database answers503 schema_too_new. - A database with migrations the code does not know answers
503 schema_too_new. Update the code; never downgrade a database by hand.
To add one, create a new sql/NNN_name.sql and append its name to SCHEMA_MIGRATIONS. Never edit an applied file.
Restore A Backup
To inspect a backup without touching the live database, restore it into a disposable one and compare:
sudo -u postgres createdb --owner=dwemer --template=template0 example_ai_restore_check
sudo -u postgres pg_restore --no-owner --role=dwemer -d example_ai_restore_check < /path/to/backup/YOUR_DATABASE.dump
sudo -u postgres psql -d example_ai_restore_check -c 'SELECT count(*) FROM ex_turns'
sudo -u postgres dropdb example_ai_restore_check
The dashboard's Verify restore does a similar check into a new <database>_verify_<random> database, so the configured database role needs CREATEDB; remove it yourself with dropdb when finished. To really restore, stop the client first, then run this. It overwrites that database:
sudo -u postgres pg_restore --clean --if-exists -d YOUR_DATABASE < /path/to/backup/YOUR_DATABASE.dump
Use this copy's configured database name (default example_ai_mod). Restore the config file from a full backup separately if needed. Run sudo bash scripts/install.sh afterwards to repair its permissions only when the checked-out code matches that backup, because it also applies migrations.
Branch And Schema Compatibility
If you offer main and dev, users can move between them in both directions, so both branches must work with the same database:
- Keep the same manifest
idandconfig_pathon every offered branch. - Make migrations additive and safe to run twice (
CREATE TABLE IF NOT EXISTS,ADD COLUMN IF NOT EXISTS). Never drop or rename what another offered branch still reads. - Add a new migration file and its
SCHEMA_MIGRATIONSentry to both branches before either offers it. A migration only ondevmakesmainrefuse that database withschema_too_new.
Template updates and failed switches. Your copy does not follow template changes; check each change you port against both branches before offering it. If a launcher branch switch fails, the launcher may put the previous code back, but it does not undo migrations already applied to the database. Restore a backup if the old code then refuses it.
Full reference: SETUP.md, Back up and update and LAUNCHER_CUSTOM_MOD.md, Branches.
Next step: Publish your own mod.
