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.
Strategy: “Brain-only”
Section titled “Strategy: “Brain-only””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 Type | Status | Location (Path) | Why? |
|---|---|---|---|
| System Config | ❌ NO | /etc/nixos | Already managed via GitHub. |
| Service Databases | ✅ YES | /var/lib/ | Home Assistant, Radarr, Sonarr, Jellyfin, etc. |
| Secrets & Keys | ✅ YES | 1Password | Fetched dynamically via 1Password CLI. |
| Downloaded Media | ❌ NO | /var/lib/media | Too 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.
| Service | Specific Data Backed Up | Exclusions (Pattern via ${stateDir}) |
|---|---|---|
| Home Assistant | SQLite DB, YAML configs, custom components, HACS state. | backups, home-assistant.log*, tts. |
| Ollama | API configuration and user state. | models/. |
| Jellyfin | User profiles, watch history, metadata database. | log/, cache/, metadata/. |
| OpenClaw | Agents, tasks, and identity state. | .npm/, *.clobbered.*, .openclaw/logs. |
| PicoClaw | Memory, sessions, and state. | .picoclaw/logs, workspace/*.log, *.bak. |
| OTBR | Thread network credentials and operational dataset. | *-tmp.data. |
| Matter Server | Matter node fabric data and credentials. | *.backup. |
| Backrest | Its own internal configuration and history. | processlogs, tasklogs, oplog.sqlite-wal. |
| Radarr/Sonarr | Media databases (SQLite), quality profiles, indexer settings. | logs/, Backups/, *.db-shm, *.db-wal. |
| Prowlarr | Indexer configurations and history. | logs/, Backups/, *.db-shm, *.db-wal. |
| Cloudflare Infra | OpenTofu state (terraform.tfstate) for Cloudflare resources. | .terraform/, secrets.env, tunnel.id, tunnel.token. |
Cloud Destination: Backblaze B2
Section titled “Cloud Destination: Backblaze B2”We use Backblaze B2 as our primary offsite storage. It is configured to run every night at 03:00 AM.
Configuration Details
Section titled “Configuration Details”- Bucket Name:
javiersc-backup - Repository URI:
b2:javiersc-backup:restic - Secrets (1Password):
- Item:
Backblaze - javiersc - Application key - Fields:
keyID,credential,restic password
- Item:
Management Interface (Backrest)
Section titled “Management Interface (Backrest)”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.
Automated Setup
Section titled “Automated Setup”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.
Access Control
Section titled “Access Control”Backrest requires browser authentication. Credentials are declaratively managed:
- User:
javiersc - Password: Stored in 1Password (
Homelab > Backrest > password)
Retention Policy
Section titled “Retention Policy”We keep a balanced history using Restic’s pruning capabilities:
| Policy | Snapshots Kept |
|---|---|
| Daily | 7 |
| Weekly | 4 |
| Monthly | 6 |
Disaster Recovery Procedure
Section titled “Disaster Recovery Procedure”For a step-by-step guide on how to use these backups to recover your system, see the Full Restore Guide.
⚠️ Manual Maintenance & Safety
Section titled “⚠️ Manual Maintenance & Safety”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.
Safe Cleanup Workflow
Section titled “Safe Cleanup Workflow”- Rewrite: Run
sudo homelab-restic-rewrite. This command automatically reads allbackupExcludesfrom your Nix configuration and removes them from all historical snapshots. - Verify: Check the snapshots via CLI (
restic snapshots) or Backrest UI. Rewritten snapshots will have a different ID and usually have therewritetag. - Prune: Once confirmed, run
sudo homelab-restic-pruneto permanently delete the data and reclaim space in Backblaze B2.
Safety Rules
Section titled “Safety Rules”- 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 --forgetcommand handles this by only keeping the cleaned versions.