backup-restore · git:20261014.1b8131c · 2026-10-14 · sha256 6f6a15929d66a36d

backup-restore git:20261014.1b8131cA

Immutable. This exact content never changes and is served at /api/v1/blob/6f6a15929d66a36d.

---
name: backup-restore
description: >-
  Manage kopiur Kopia-based backups and restores for Kubernetes PVs in this cluster.

  user: "check backup status for app X" → describe the SnapshotPolicy/SnapshotSchedule
  user: "restore from backup" → follow the restore workflow below
  user: "trigger manual backup" → `kubectl kopiur snapshot now --policy <app> -n <ns> --wait`
  user: "backup failing" → delegate to debug-cluster for mover pod logs

  Use when the user mentions backups, restores, snapshots, SnapshotPolicy, SnapshotSchedule,
  Restore, ClusterRepository, PVC recovery, or disaster recovery. This cluster uses kopiur
  (home-operations, kopia-native), not VolSync, not restic.
compatibility: Requires `kubectl` access to the cluster and the `kopiur` kubectl plugin; kopiur CRDs and the shared ClusterRepository secret must exist.
---

# Backup and restore (kopiur + Kopia)

## Quick reference

| Operation | Command |
|-----------|---------|
| List policies | `kubectl get snapshotpolicy -A` |
| List schedules | `kubectl get snapshotschedule -A` |
| List snapshots for an app | `kubectl kopiur snapshots list --policy <app> -n <ns>` |
| Trigger manual snapshot | `kubectl kopiur snapshot now --policy <app> -n <ns> --wait` |
| Check a restore | `kubectl get restore <app>-restore -n <ns>` |
| Status | `kubectl describe snapshotpolicy <app> -n <ns>` |

## Check status

A healthy policy shows `Ready: True` and a recent `status.lastSuccessfulSnapshot`. The
`SnapshotSchedule` object's `status.observedGeneration` sticking behind
`.metadata.generation` is a known cosmetic quirk (fleet-wide, harmless) — it makes the owning
Flux Kustomization's `wait: true` health check flap (`HealthCheckFailed ... status: 'InProgress'`,
self-clears on retry). Don't chase it; trust the policy's own `Ready` condition and a fresh
manual snapshot instead.

## Restore from backup

The procedure is [docs/kopiur-restore.md](../../../docs/kopiur-restore.md): suspend both
Kustomization and HelmRelease, pause KEDA, scale down every deployment sharing the PVC, delete
the PVC, resume, verify. That file is the single copy, and also covers point-in-time restore
(`offset`/`asOf`/`snapshotRef`/`identity`), the `Completed`/`Ready: False` sweep, and the live-uid
check.

Not in that file: when the live uid does not match the manifest's `runAsUser`,
`KOPIUR_PUID`/`KOPIUR_PGID` (and, only for genuine root,
`KOPIUR_MOVER_CAPS_ADD: "[DAC_READ_SEARCH]"`) go in the app's own `ks.yaml`
`postBuild.substitute` block — see [references/restore-pvc.md](references/restore-pvc.md).

## Enable backups for a new app

Reference patterns in `kubernetes/components/kopiur/`. See
[references/restore-pvc.md](references/restore-pvc.md) for the full substitute-variable list.

## Troubleshooting (inline)

- Repository secret: `kubectl get secret -n kopiur-system kopia-nas-password` (shared across all apps
  via credential projection — apps don't carry their own copy)
- `ClusterRepository` health: `kubectl get clusterrepository kopia-nas`

Symptom-keyed failures (PVC never claimed, restore stalling, wrong `dataSourceRef`, mover stuck
with no output) → [docs/kopiur-restore.md](../../../docs/kopiur-restore.md) Troubleshooting.
For mover logs and deep failures → [debug-cluster](../debug-cluster/SKILL.md).