Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export default defineConfig({
items: [
{ text: 'Deployment', link: '/deployment' },
{ text: 'Upgrading', link: '/upgrading' },
{ text: 'Backup & restore', link: '/backup-restore' },
{ text: 'Configuration reference', link: '/configuration' },
{ text: 'Configuration generator', link: '/configuration/generator' },
{ text: 'Authentication', link: '/authentication' },
Expand Down
68 changes: 68 additions & 0 deletions apps/docs/backup-restore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
title: Backup & restore
lang: en-US
---

# Backup & restore

Piwi's migrations are **forward-only** — once a new version has migrated your database, an older version will not run against it correctly. So a backup is not just insurance against disk loss; it is the *only* rollback path. Take one before every version bump.

## What to back up

Everything lives in two places — back up both, together:

1. **The database** — the SQLite file `.data/piwi.db` (the default), or your PostgreSQL database.
2. **File storage** — `.data/storage/` (HTML reports, traces, attachments), unless you keep artifacts in [S3](./storage#s3-compatible-storage), in which case the bucket is your storage backup.

The two must be consistent with each other: a database row points at a stored trace, so a backup that captures one without the other can dangle. The simplest way to guarantee consistency is to stop the container before copying; the online methods below avoid the downtime.

## Backing up

::: code-group

```bash [SQLite (online, no downtime)]
# Consistent SQLite snapshot without stopping the server, plus the storage dir
sqlite3 .data/piwi.db ".backup '.data/piwi-backup.db'"
tar czf piwi-backup.tar.gz -C .data piwi-backup.db storage
```

```bash [PostgreSQL]
pg_dump "$PIWI_DATABASE_URL" > piwi-db.sql
tar czf piwi-storage.tar.gz -C .data storage # skip if artifacts are in S3
```

```powershell [Windows (stop first)]
# Stop the container for a consistent copy, then archive .data
Compress-Archive -Path .data -DestinationPath piwi-backup.zip
```

:::

If artifacts are in S3, lean on the bucket's own durability and versioning rather than copying `.data/storage/`. Keep the database backup and the storage backup from the *same moment* so they agree.

## Restoring

Restoring is also how you roll back after an upgrade goes wrong — the rollback path is "restore your backup", never "pull the old tag" against an already-migrated database.

1. **Stop the container.**
2. **Restore the database and `.data/storage/`** from a backup pair taken at the same time. For SQLite, put `piwi-backup.db` back as `.data/piwi.db` and unpack the storage archive; for PostgreSQL, restore the dump into an empty database (`psql "$PIWI_DATABASE_URL" < piwi-db.sql`).
3. **Start the version the backup was taken on.** A backup from version *N* must be restored under version *N* (or newer, which will migrate it forward) — not an older one.

Then confirm the running version at **Settings → About**, and that recent runs are present. See [Upgrading](./upgrading) for the full version-change story and the checks that tell you a migration landed.

## The desktop app

The [desktop build](./desktop) bundles its own server, and its database and storage live in a per-machine data directory *outside* the app bundle, migrated on first launch exactly as the server does — so the same forward-only rule applies. Back up that data directory before a major version jump; a newer build will migrate it, an older one cannot open it.

## When to back up

- **Before every version bump** — this is the one that matters, because it is the only rollback path.
- **On a schedule** matched to how much history you would hate to lose — nightly is plenty for most teams.
- Retention pruning deletes runs permanently; if you want a longer tail than your [retention window](./storage#data-retention) keeps, a periodic backup is where that history lives.

## Related

- [Upgrading](./upgrading) — forward-only migrations and verifying an upgrade
- [Deployment](./deployment) — the volume layout and resource sizing
- [Database](./database) — SQLite versus PostgreSQL
- [Storage → Data retention](./storage#data-retention) — what the nightly sweep prunes
26 changes: 2 additions & 24 deletions apps/docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,31 +405,9 @@ When auth is enabled, set `PIWI_SITE_URL` to the public HTTPS URL so email links

## Backups

Everything lives in two places — back both up:
Everything lives in two places — the database (`.data/piwi.db` or your PostgreSQL database) and file storage (`.data/storage/`, unless you use [S3](/storage)). Back up both, together, before every version bump: migrations are forward-only, so a backup is the only rollback path.

1. **The database** — SQLite file `.data/piwi.db` (default) or your PostgreSQL database (`pg_dump`).
2. **File storage** — `.data/storage/` (HTML reports, traces, attachments), unless you use [S3 storage](/storage).

With the default SQLite + local storage setup, a consistent backup is simply a copy of `.data/` while the container is stopped — or use SQLite's online backup to avoid downtime:

::: code-group

```bash [Linux / macOS]
# Online, consistent SQLite backup + storage copy
sqlite3 .data/piwi.db ".backup '.data/piwi-backup.db'"
tar czf piwi-backup.tar.gz -C .data piwi-backup.db storage
```

```powershell [Windows (PowerShell)]
# Stop the container first for a consistent copy, then:
Compress-Archive -Path .data -DestinationPath piwi-backup.zip
```

:::

With PostgreSQL: `pg_dump` the database and copy `.data/storage/` (or rely on your S3 bucket's own durability/versioning).

Take one before every version bump: migrations are forward-only, so a backup is the only rollback path. See [Upgrading](./upgrading).
The full procedure — online SQLite snapshots, `pg_dump`, restoring, and the desktop app's data directory — is on [Backup & restore](./backup-restore).

## Resource requirements

Expand Down
Loading