Skip to main content

Upgrades and backups

All MiniPAM state lives in one SQLite database: database.db. Back it up and you have backed up MiniPAM. Its location is set by server.database.location.

MiniPAM uses SQLite's WAL (write-ahead log) mode. While the server runs, recent changes may sit in database.db-wal next to the database, with an index in database.db-shm. The file database.db on its own is not a complete copy. Keep all three on a local disk or Docker volume, not on a network share (NFS, SMB): SQLite's file locking does not work reliably there.

Back up​

Use SQLite's own backup command. It produces a consistent copy in one file, even while the server is running:

sqlite3 /path/to/database.db ".backup 'minipam-$(date +%F).db'"

Copy the files by hand only with the server stopped, and copy database.db-wal and database.db-shm too if they exist.

With Docker, the file is in the minipam-data volume. Stop the container and copy the volume, or run the backup from a throwaway container that mounts it:

docker run --rm -v minipam-data:/data -v "$PWD":/backup alpine \
sh -c 'apk add --no-cache sqlite >/dev/null && sqlite3 /data/database.db ".backup /backup/minipam-$(date +%F).db"'

Keep backups private. They contain your whole network layout.

Data transfer (under Administration → System) exports inventory as JSON or XLSX. It is useful for moving records or editing them in bulk, but it is not a backup: it leaves out users, history, jobs, and template revisions.

Upgrade​

  1. Back up the database.
  2. Stop every MiniPAM server that uses the file. Two versions must never share one database.
  3. Update and start the new version, as shown below.

From source, pull the new code, then repeat Install the server and Build the web interface. Start the server again with cli.py run --config config.local.yml.

With Docker, rebuilding the image does not change a container that already exists. Rebuild, then replace the container with the same docker run command as the quick start:

docker build -f deployments/docker/server.Dockerfile -t minipam-server .
docker rm -f minipam
docker run -d --name minipam \
-p 8091:8091 \
-v minipam-data:/var/lib/minipam \
-v "$PWD/minipam-config.yml:/app/app-server/config.yml:ro" \
--restart unless-stopped \
minipam-server

The database is in the minipam-data volume, so removing the container keeps it. With Docker Compose, rebuild the image, then run docker compose up -d: it recreates the container from the new image.

On start, MiniPAM checks the database version and applies any pending migrations before it accepts traffic. Agents keep running during the upgrade and reconnect when the server is back. An agent gives up after about an hour of failed attempts; see An agent stopped reconnecting.

If an upgrade fails​

Before migrating, MiniPAM writes a copy next to the database and checks it with SQLite's PRAGMA quick_check:

database.db.pre-migration.bak

If a migration fails, MiniPAM restores that copy itself, logs the error, and refuses to start. Install the previous version again, or report the error.

Inspect and manage the database version with these commands, run from app-server:

../.venv/bin/python cli.py db status --config config.local.yml
../.venv/bin/python cli.py db upgrade --config config.local.yml
../.venv/bin/python cli.py db backup-before-migration --config config.local.yml
../.venv/bin/python cli.py db restore-migration-backup --config config.local.yml

With Docker, run them in the running container, for example:

docker exec -it minipam python cli.py db status

See Command line.

restore-migration-backup replaces the database with the safety copy and asks for confirmation. Stop the server first. With Docker, docker exec needs a running container, so run the restore in a temporary one that mounts the same volume and configuration:

docker stop minipam
docker run --rm -it \
-v minipam-data:/var/lib/minipam \
-v "$PWD/minipam-config.yml:/app/app-server/config.yml:ro" \
minipam-server python cli.py db restore-migration-backup
docker start minipam

The safety copy is overwritten by the next migration, so it does not replace your own dated backups.

Pre-alpha

During pre-alpha, the migration history may be reset between versions. When that happens the release notes say so, and the database has to be recreated. Export your inventory with Data transfer first and import it into the new database.

Compact the database​

Deleting rows does not shrink the SQLite file. The space is kept as free pages and reused for new data. After a large cleanup, for example after lowering a retention setting or deleting many records, db vacuum gives that space back to the disk. Run it when Database usage (or cli.py db usage) shows a large share of the file as free. Routine use does not need it. It prints the size before and after. Run it from app-server:

../.venv/bin/python cli.py db vacuum --config config.local.yml

With Docker:

docker exec minipam python cli.py db vacuum

Before you run it:

  • Free disk space. It writes a new copy of the database, so it needs about as much free space as the database's size.
  • It blocks writers. While it runs, other writers wait. If they wait more than 5 seconds, they fail with "database is locked", so scans, jobs, and edits can fail.
  • Stop the server first, if you can. If the command cannot get the lock within 5 seconds, it fails without changing anything. With Docker, stop the container and run the command in a temporary one, as for restore-migration-backup above.