Skip to content
This repository was archived by the owner on Jun 27, 2026. It is now read-only.

Latest commit

 

History

History
178 lines (134 loc) · 6 KB

File metadata and controls

178 lines (134 loc) · 6 KB

Runbook — Restore from backup

This is the canonical recovery procedure when the stack's database or user-uploaded content is lost, corrupted, or needs to be rolled back to a known-good snapshot. Backups are produced nightly by the backup service (see config/phpbu/backup.json).

Backup artefacts

Located in the snipeit-backups volume (bind-mount it onto an off-host share for disaster-survival), organised into three subdirectories:

Path What Cadence Retention
/backups/db/snipeit-db-*.sql.gz mariadb-dump of the application DB (single-transaction, routines + triggers) nightly 03:00 rolling 5 GB
/backups/uploads/snipeit-uploads-*.tar.gz tar of app-data volume (Snipe-IT uploads / EULAs / barcodes) nightly 03:00 30 days
/backups/storage/snipeit-storage-*.tar.gz tar of app-storage volume (Laravel storage, including the cached config) nightly 03:00 30 days
/backups/phpbu.log structured JSON log of phpbu runs (success and failure) per-run append rotated by phpbu

make backup-list shows what's currently on disk.

Restore — full disaster (DB + uploads + storage)

1. Stop the running stack

docker compose stop app web scheduler
# Leave `db`, `valkey`, and `backup` up — we need db to receive the restore.

2. Identify the snapshot to restore from

make backup-list
# Pick the SQL file you want — typically the most recent. Note the timestamp.
TIMESTAMP=20260521-030001   # adjust to your chosen file

3. Drop and recreate the application database

This is destructive. The mariadb-dump artefact contains the schema and data — we're swapping in the backed-up state wholesale.

docker compose exec -T db sh -c '
  mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" -e "
    DROP DATABASE IF EXISTS snipeit;
    CREATE DATABASE snipeit CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    GRANT ALL ON snipeit.* TO snipeit@'%';
    FLUSH PRIVILEGES;"'

4. Replay the SQL dump

docker compose exec -T backup sh -c "
  zcat /backups/db/snipeit-db-${TIMESTAMP}.sql.gz" \
  | docker compose exec -T db sh -c '
    mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" snipeit'

For a large dump this can take minutes — let it finish.

5. Restore the uploads volume

docker compose run --rm -v snipeit-app-data:/restore \
  backup sh -c "
    cd /restore && \
    rm -rf ./* ./.[!.]* 2>/dev/null || true && \
    tar xzf /backups/uploads/snipeit-uploads-${TIMESTAMP}.tar.gz --strip-components=2"

--strip-components=2 peels the /snapshot/data/ prefix that phpbu added when it captured the tree.

6. Restore the storage volume

docker compose run --rm -v snipeit-app-storage:/restore \
  backup sh -c "
    cd /restore && \
    rm -rf ./* ./.[!.]* 2>/dev/null || true && \
    tar xzf /backups/storage/snipeit-storage-${TIMESTAMP}.tar.gz --strip-components=2"

7. Clear caches and bring the stack back up

The restored storage volume contains the old cached config. Clear it before the app re-mounts the cache:

docker compose run --rm app sh -c "
  rm -f bootstrap/cache/config.php bootstrap/cache/routes-*.php bootstrap/cache/events.php"
docker compose start app web scheduler
docker compose logs -f --tail=50 app

8. Verify

# 1. HTTP responds:
curl -sI http://localhost:8000/login | head -1

# 2. Log in via browser and confirm assets visible.
# 3. Compare a known asset count:
docker compose exec -T db sh -c '
  mariadb -usnipeit -p"$DB_PASSWORD" -e "SELECT COUNT(*) FROM assets;" snipeit'

Restore — database only

Skip steps 5 and 6. App will use its current uploads + storage with the restored DB. Useful for "undo an incorrect bulk update on assets" type incidents.

Caveat: if the DB references uploaded files (avatars, EULAs) that were added after the snapshot, those files exist on disk but Snipe-IT won't reference them (they're orphans). And uploads referenced by the restored DB that were deleted later are missing 404s. For point-in-time fidelity, restore all three.

Restore — older revision via binlog (advanced)

The DB service has --log-bin=mariadb-bin --binlog-format=ROW --expire-logs-days=14 enabled, so PITR within the last 14 days is possible:

# 1. Restore the latest dump BEFORE the bad event
# 2. Apply binlogs up to a specific timestamp:
docker compose exec -T db sh -c '
  mariadb-binlog --start-datetime="2026-05-21 09:00:00" \
                 --stop-datetime="2026-05-21 14:30:00" \
                 /var/lib/mysql/mariadb-bin.* \
  | mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" snipeit'

Rollback to a previous image tag

If the issue is a broken Snipe-IT release, not lost data:

# .env: set SNIPE_IT_IMAGE_TAG=8.5.0-20260520  (or any dated tag)
docker compose pull app app-assets
docker compose up -d
# Migrations roll forward; the image carries its own migration state.

Note: Snipe-IT migrations are forward-only. Restoring an older image against a DB migrated by a newer image will produce schema errors. In that case do a full DB+image restore from the corresponding day's snapshot.

Backup-verify (read-only sanity check)

make backup-verify runs phpbu in --simulate mode, plus checks that last night's dump is on disk and not zero-byte. It does NOT restore — use it to confirm the backup pipeline is working without disrupting production.

Off-host shipping

snipeit-backups is a local Docker volume. Survives container restart but not host loss. For real disaster recovery, configure your existing backup tool (restic, rclone, BorgBackup, etc.) to read from the volume mount point on the host. Example bind-mount snippet for compose.yml:

backup:
  volumes:
    - /mnt/nas/snipeit-backups:/backups   # NAS-mounted destination

Replace /mnt/nas/snipeit-backups with your real destination. The phpbu config is unchanged — it still writes to /backups inside the container; that path is now on your NAS.