Skip to content

Backups

The backup system is built on Restic, with a purely declarative configuration managed via Backrest Plans. This ensures that the backup schedule, retention, and exclusions are 100% reproducible while providing a powerful web UI for monitoring and recovery.

We follow a strategy that prioritizes the “Brain” (configurations, databases, and code) over the “Muscles” (heavy media files). This keeps cloud costs low and recovery times fast.

Data TypeStatusLocation (Path)Why?
System Config❌ NO/etc/nixosAlready managed via GitHub.
Service Databases✅ YES/var/lib/Home Assistant, Radarr, Sonarr, Jellyfin, etc.
Secrets & Keys✅ YES1PasswordFetched dynamically via 1Password CLI.
Downloaded Media❌ NO/var/lib/mediaToo large (TBs).

The following services have their entire state (databases, configurations, and internal state) backed up. Each service declares its own rules in its .nix file:

  • homelab.backupPaths: Directories to include.
  • homelab.backupExcludes: Specific paths to ignore. Important: These must be defined in the service module using the ${stateDir} variable and must be sorted alphabetically.
  • homelab-restic-rewrite: Command to purge junk/logs from history declaratively.
  • homelab-restic-prune: Command to reclaim space from B2 safely.
ServiceSpecific Data Backed UpExclusions (Pattern via ${stateDir})
Home AssistantSQLite DB, YAML configs, custom components, HACS state.backups, home-assistant.log*, tts.
OllamaAPI configuration and user state.models/.
JellyfinUser profiles, watch history, metadata database.log/, cache/, metadata/.
OpenClawAgents, tasks, and identity state..npm/, *.clobbered.*, .openclaw/logs.
PicoClawMemory, sessions, and state..picoclaw/logs, workspace/*.log, *.bak.
OTBRThread network credentials and operational dataset.*-tmp.data.
Matter ServerMatter node fabric data and credentials.*.backup.
BackrestIts own internal configuration and history.processlogs, tasklogs, oplog.sqlite-wal.
Radarr/SonarrMedia databases (SQLite), quality profiles, indexer settings.logs/, Backups/, *.db-shm, *.db-wal.
ProwlarrIndexer configurations and history.logs/, Backups/, *.db-shm, *.db-wal.
Cloudflare InfraOpenTofu state (terraform.tfstate) for Cloudflare resources..terraform/, secrets.env, tunnel.id, tunnel.token.

We use Backblaze B2 as our primary offsite storage. It is configured to run every night at 03:00 AM.

  • Bucket Name: javiersc-backup
  • Repository URI: b2:javiersc-backup:restic
  • Secrets (1Password):
    • Item: Backblaze - javiersc - Application key
    • Fields: keyID, credential, restic password

Backrest provides a Web UI to interact with Restic. In this infrastructure, Backrest is fully declarative. The repository connection and authentication are automatically configured on boot using the secrets fetched from 1Password.

While NixOS manages the background timers, Backrest is used for:

  • Monitoring the health of daily backups.
  • Exploring snapshots and performing granular restores.
  • Manual triggers for ad-hoc backups.

Unlike standard installations, you do NOT need to manually add the repository or environment variables. The service is hardened and pre-configured to point to your Backblaze B2 bucket immediately after deployment.

Backrest requires browser authentication. Credentials are declaratively managed:

  • User: javiersc
  • Password: Stored in 1Password (Homelab > Backrest > password)

We keep a balanced history using Restic’s pruning capabilities:

PolicySnapshots Kept
Daily7
Weekly4
Monthly6

For a step-by-step guide on how to use these backups to recover your system, see the Full Restore Guide.


When performing manual cleanup (e.g., removing “junk” or secrets from history), use the built-in Homelab Restic Toolkit to avoid authentication errors and ensure consistency with NixOS excludes.

  1. Rewrite: Run sudo homelab-restic-rewrite. This command automatically reads all backupExcludes from your Nix configuration and removes them from all historical snapshots.
  2. Verify: Check the snapshots via CLI (restic snapshots) or Backrest UI. Rewritten snapshots will have a different ID and usually have the rewrite tag.
  3. Prune: Once confirmed, run sudo homelab-restic-prune to permanently delete the data and reclaim space in Backblaze B2.
  • Don’t Manual Auth: Avoid exporting B2 keys manually; use the toolkit scripts which handle secrets via /run/restic/.
  • Check Groups: Restic organizes snapshots by their Host and the exact list of Paths. If you change paths, Restic starts a new group. The homelab-restic-rewrite --forget command handles this by only keeping the cleaned versions.