Skip to content

Backups

Kestrel stores everything that matters under one directory tree. Backing up is one command.

Take a snapshot

bash
kestrel backup /var/backups/kestrel-$(date +%F).tar.gz

Or, inside the Docker container:

bash
docker exec kestrel /kestrel backup /data/snapshot.tar.gz
docker cp kestrel:/data/snapshot.tar.gz ./

Behind the scenes, kestrel backup:

  1. Runs SQLite VACUUM INTO against a temp file. This is a transactional snapshot — the live server keeps taking writes during the backup, and the resulting file is fully self-contained (no WAL sidecar required).
  2. Walks the sourcemap directory tree and appends every .map file under sourcemaps/.
  3. Emits a single .tar.gz archive: kestrel.db at the root and sourcemaps/<project>/<release>/<file>.map for each map.

Restore

A restore is a plain tar extraction followed by a path swap:

bash
# 1. Stop the running server (so we're not racing on the data dir)
docker stop kestrel

# 2. Extract the archive over the data volume
docker run --rm -v kestrel-data:/data -v $PWD:/in alpine \
  sh -c 'tar -xzf /in/snapshot.tar.gz -C /data'

# 3. Start the server back up
docker start kestrel

The DB, sourcemaps, admin password file, and session secret all live under /data, so the restored container behaves identically to the source. Project tokens are unchanged because their hashes survive the round trip.

Scheduling

Run kestrel backup from cron / systemd timer / Kubernetes CronJob — there's no API to call, just a CLI invocation. Rotate old archives with whatever you already use (tmpwatch, logrotate, S3 lifecycle rules).

What's not in the backup

  • The auto-generated .admin_password file. If you lose access, restart the server with KESTREL_ADMIN_PASSWORD=... set; that takes precedence over the file. Or delete the file before next start to regenerate.
  • Anything in KESTREL_DATA outside the DB and sourcemaps tree. Custom integrations that drop files there should back them up separately.

Sanity-checking a snapshot

The archive's kestrel.db is a normal SQLite file. To poke at it without restoring:

bash
tar -xzf snapshot.tar.gz kestrel.db
sqlite3 kestrel.db 'SELECT COUNT(*) FROM events; SELECT COUNT(*) FROM issues;'

If those numbers look right, the backup is good.

Released under the MIT License.