Backup and restore
Back up the database with slopscale db backup while the server runs, verify and restore a backup, schedule nightly copies, and back up PostgreSQL.
Slopscale keeps everything it knows in one database: users, machines and their keys, pre-auth keys, API keys, the policy and the settings. A backup of that database plus the configuration directory is a backup of the whole control server.
Why copying the file is not enough
A SQLite database in write-ahead log mode is three files: db.sqlite,
db.sqlite-wal and db.sqlite-shm. Recent writes live in the log until
SQLite folds them back into the main file, so the main file on its own is
missing them. cp reads the three at different moments while the server
keeps writing, and the result can be a database that is inconsistent, or a
main file paired with a log that no longer matches it. A copy taken from a
stopped server is fine; a copy taken from a running one is a gamble.
slopscale db backup asks SQLite for the copy instead, in one transaction,
and writes a single file with no log beside it. It is safe to run while the
server is serving.
Back up
sudo -u slopscale slopscale db backup
The backup lands next to the database as <database>.backup-<timestamp>.
Write it somewhere else with --out:
sudo -u slopscale slopscale db backup --out /var/lib/slopscale/backups/db-2026-01-31.sqlite
The command refuses to overwrite an existing file, and the copy is read back before it takes its final name, so an interrupted backup leaves nothing behind.
Back up the configuration directory too. It holds config.yaml, the private
keys the server identifies itself with and, unless you keep the policy in
the database, the policy file. None of them are in the database:
tar -czf /var/lib/slopscale/backups/etc-2026-01-31.tar.gz /etc/slopscale
Check a backup
slopscale db verify /var/lib/slopscale/backups/db-2026-01-31.sqlite
Verify runs SQLite’s integrity check, confirms the file carries the slopscale migration history, and compares the version that last wrote it with the binary you run it with, so a backup from a newer server is reported before you try to restore it. Restore verifies the file the same way, so this is for checking that yesterday’s backups are still good.
Restore
Restoring replaces the live database. Stop the server first: it holds the database open and would carry on with the copy it started with.
sudo systemctl stop slopscale
sudo -u slopscale slopscale db restore /var/lib/slopscale/backups/db-2026-01-31.sqlite
sudo systemctl start slopscale
The current database is not deleted. It is moved to
<database>.pre-restore-<timestamp>, together with its write-ahead log, so
a restore of the wrong file can be undone by moving it back. The command
asks for confirmation; --yes skips the question for scripts.
Machines reconnect on their own after the restart. A machine that was registered after the backup was taken is unknown to the restored database and has to register again.
Take one every night
The command writes the file, it does not create the directory it goes in:
sudo install -d -o slopscale -g slopscale -m 0700 /var/lib/slopscale/backups
# The field after the schedule is the user to run as, and percent signs
# must be escaped in a crontab.
0 3 * * * slopscale slopscale db backup --out /var/lib/slopscale/backups/db-$(date +\%Y\%m\%d).sqlite
15 3 * * * slopscale find /var/lib/slopscale/backups -name 'db-*.sqlite' -mtime +14 -delete[Unit]
Description=Back up the slopscale database
[Service]
Type=oneshot
User=slopscale
ExecStart=/bin/sh -c '/usr/bin/slopscale db backup --out /var/lib/slopscale/backups/db-$(date +%%Y%%m%%d).sqlite'[Unit]
Description=Back up the slopscale database nightly
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.targetsudo systemctl enable --now slopscale-backup.timerContainers
Back up from the container that already has the configuration file and the data volume. The date is expanded by the shell on the host, so the image needs no shell of its own:
mkdir -p ./slopscale/lib/backups
docker exec slopscale slopscale db backup \
--out /var/lib/slopscale/backups/db-$(date +%Y%m%d).sqlite
Restoring needs the server stopped, so run a second container over the same
volumes with db restore in place of serve:
docker stop slopscale
docker run --rm \
--volume "$(pwd)/config:/etc/slopscale:ro" \
--volume "$(pwd)/lib:/var/lib/slopscale" \
ghcr.io/aislopware/slopscale:<VERSION> \
db restore /var/lib/slopscale/backups/db-20260131.sqlite --yes
docker start slopscale
PostgreSQL
slopscale db only handles SQLite. A PostgreSQL database is backed up with
the tools that ship with the server:
pg_dump --format=custom --file=slopscale-2026-01-31.dump --host=localhost --username=slopscale slopscale
Restore it into an empty database with pg_restore:
pg_restore --dbname=slopscale --host=localhost --username=slopscale slopscale-2026-01-31.dump
See PostgreSQL’s Backup and Restore documentation for the options, and stop slopscale before restoring, as with SQLite.