# Back up, restore, and upgrade Nibleaf

> Capture Postgres and object storage as one recovery set, test restoration in isolation, and upgrade or roll back a pinned Nibleaf release.

A usable recovery set includes Postgres and object storage from the same
operational window. A database dump without uploaded assets is incomplete. Keep
copies outside the live host and account, and prove restoration before relying
on them.

## Create a backup

From a repository checkout, the bundled script defaults to
`docker-compose.prod.yml`, `./backups`, 14-day local retention, and the bundled
maxio volume:

```bash
./scripts/backup.sh
```

For a guided-installer directory where the Compose file is named
`docker-compose.yml`, point the script at that file:

```bash
COMPOSE_FILE=docker-compose.yml ./scripts/backup.sh
```

The script creates a custom-format `pg_dump` and, when the configured Docker
volume exists, a compressed storage archive. External R2 or S3 buckets are not
captured by the Docker-volume step; use provider versioning, replication, or an
independent bucket backup.

Ship both artifacts off-host with separate credentials and record identifiers,
sizes, timestamps, retention, and the application release.

## Test a restore

Never overwrite production for a drill. Create an isolated database, storage
target, and application origin. Follow the restore commands documented at the
top of `scripts/backup.sh`, then verify projects, memberships, page trees,
current drafts, ready deployments, uploaded assets, authentication isolation,
and public search.

Record elapsed time and every manual step. A backup job exit code without a
successful isolated restore is not recovery evidence.

## Upgrade a pinned release

Read each intervening release note and check for release-specific migration or
configuration changes. Create and restore-test a backup, then change
`NIBLEAF_VERSION` to an existing release tag in `.env`:

The six August 2026 capabilities are currently merged source, while the
published self-host manifest remains v0.1.2. Do not invent a newer tag or replace
the committed installer and Compose digests. When a matching future artifact is
available, use the [combined release migration guide](/self-hosting/combined-release-migration)
for its search, usage, add-on, integration, and MCP dependency order.

```dotenv
NIBLEAF_VERSION=vX.Y.Z
```

Pull and recreate the services:

```bash
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
```

Confirm the image digest, migration log, service health, sign-in, one upload,
one publish, one search, and one public page.

## Roll back safely

If no schema migration ran, pin the prior image and recreate the services. If a
forward-only migration changed the database, stop writes and restore the
pre-upgrade recovery set before starting the older application.

For the combined capability schema, prefer runtime rollback and reverse MCP,
integrations, add-ons, usage, then search only after deploying code that no
longer reads the removed state. The integrations migration owns the shared
nullable `ApiKey.expiresAt`; do not remove it while MCP or another consumer
depends on it.

Do not combine an application upgrade with a PostgreSQL major-version change.
Treat the database upgrade as a separate dump-and-restore project.
