Skip to content

Latest commit

 

History

58 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Kartoza ZFS Backup Tool

A beautiful TUI (Terminal User Interface) for managing ZFS backups, built with Bubble Tea and Lipgloss.

Release License Documentation

📖 Full Documentation

Features

  • Incremental Backups - Efficient snapshots of your chosen datasets with syncoid integration
  • Backup Scope - Pick exactly which datasets are backed up; everything else is never touched
  • Health Check - doctor finds orphaned snapshots and quota pressure before it bites
  • Multi-Host Backups - Back up multiple machines to the same drive with hostname namespacing
  • Pull Backup From Remote - Pull ZFS snapshots from remote servers via SSH
  • Push Backup to Remote - Push local snapshots to a remote backup server via SSH
  • Force Backup - Destructive backup option for out-of-sync scenarios
  • Restore Files - Dual-panel file explorer to browse snapshots and restore files
  • Pool Information - View detailed pool structure, health, datasets, and snapshots
  • Pool Maintenance - Start, stop, and monitor scrub operations
  • Device Preparation - Create encrypted ZFS pools with AES-256-GCM
  • Safe Unmounting - Properly export pools and power off USB drives
  • Smart Pool Defaults - Auto-detects source/destination pools based on naming
  • Saved Host Profiles - Remote hosts are persisted for quick reuse
  • CLI Mode - Command-line arguments for automation and scripting

Backup Modalities

Local Backup (to external USB drive)

graph LR
    subgraph "Local Machine"
        A[NIXROOT/home]
        B[NIXROOT/nix]
        C[NIXROOT/root]
    end
    subgraph "USB Backup Drive"
        D[NIXBACKUPS/abyss/home]
        E[NIXBACKUPS/abyss/nix]
        F[NIXBACKUPS/abyss/root]
    end
    A -->|syncoid| D
    B -->|syncoid| E
    C -->|syncoid| F
Loading

Pull Backup From Remote (remote server to local drive)

graph LR
    subgraph "Remote Server (myserver)"
        A[NIXROOT/home]
        B[NIXROOT/nix]
    end
    subgraph "Local USB Backup Drive"
        D[NIXBACKUPS/myserver/home]
        E[NIXBACKUPS/myserver/nix]
    end
    A -->|"syncoid (SSH pull)"| D
    B -->|"syncoid (SSH pull)"| E
Loading

Push Backup (local to remote backup server)

graph LR
    subgraph "Local Machine"
        A[NIXROOT/home]
        B[NIXROOT/nix]
    end
    subgraph "Remote Backup Server"
        D[NIXBACKUPS/abyss/home]
        E[NIXBACKUPS/abyss/nix]
    end
    A -->|"syncoid (SSH push)"| D
    B -->|"syncoid (SSH push)"| E
Loading

Multi-Host on Same Drive

graph TB
    subgraph "USB Backup Drive (NIXBACKUPS)"
        subgraph "abyss (laptop)"
            A1[home]
            A2[nix]
            A3[root]
        end
        subgraph "myserver (remote)"
            B1[home]
            B2[nix]
            B3[data]
        end
        subgraph "workstation (remote)"
            C1[home]
            C2[projects]
        end
    end
Loading

All datasets — including application-managed datasets without a regular mountpoint, such as atuin — are namespaced by hostname so multiple machines can share one backup drive without conflicts. Every backup target lives under NIXBACKUPS/<hostname>/<dataset> (for example NIXBACKUPS/abyss/home, NIXBACKUPS/abyss/atuin).

Automatic migration from the legacy flat layout. Earlier versions wrote some datasets to a flat path such as NIXBACKUPS/home. At the start of every backup, the tool detects any remaining flat-layout datasets and atomically renames them into the hostname namespace (zfs rename NIXBACKUPS/home NIXBACKUPS/<hostname>/home). If a dataset already exists at both the flat and the namespaced location the migration aborts with a clear error so you can resolve the conflict manually — the backup will never silently merge or destroy snapshots.

Quick Start

Install

# Download binary (Linux x86_64)
curl -L https://github.com/timlinux/zfs-backup/releases/latest/download/zfs-backup-linux-amd64 -o zfs-backup
chmod +x zfs-backup
sudo mv zfs-backup /usr/local/bin/

# Or with Nix
nix run github:timlinux/zfs-backup

See Installation Guide for more options including NixOS, Arch (AUR), Debian, Fedora, Snap, and Flatpak.

Run

# Interactive mode
sudo zfs-backup

# CLI mode
sudo zfs-backup --backup      # Run incremental backup
sudo zfs-backup --unmount     # Safely unmount backup drive
sudo zfs-backup --help        # Show help

# Scope, health and cleanup - all three are also main-menu items
sudo zfs-backup scope                      # Show which datasets are backed up
sudo zfs-backup scope --datasets home      # Back up only POOL/home
sudo zfs-backup doctor                     # Read-only health check
sudo zfs-backup cleanup-orphans            # Dry run: what would be reclaimed

What zfs-backup touches

zfs-backup only ever snapshots the datasets it also replicates and prunes. Anything outside the backup scope — datasets you excluded, nested child datasets, the pool root itself — is never snapshotted, never replicated and never pruned.

By default the scope is every top-level dataset of the source pool. Narrow it with the Backup Scope menu item or zfs-backup scope --datasets a,b.

Pruned snapshots become bookmarks, so incremental sends keep working without holding the snapshot data. Only snapshots matching zfs-backup's own naming pattern (2026-08-14.10h-00-Backup) are ever pruned or destroyed — sanoid autosnaps, your own snapshots, and @blank are left strictly alone.

Upgrading from 1.x? Choose your Backup Scope first - with no scope set, every top-level dataset counts as in scope, so the old debris looks managed and the health check will report almost nothing. Scope, then check, then clean.

Why it happened: Versions before 2.0.0 took a recursive snapshot of the whole pool but only pruned one dataset, so -Backup snapshots accumulated on datasets that were never meant to be backed up. Open Backup Health Check from the menu to see whether you are affected, then press c to clean it up - it shows a dry run first and asks you to type DESTROY before removing anything. sudo zfs-backup doctor and sudo zfs-backup cleanup-orphans do the same from a script.

quota vs refquota

This distinction decides how visible a snapshot leak is:

Property Counts snapshots? Symptom when snapshots pile up
quota Yes — dataset plus its snapshots and descendants The dataset hits its limit and writes fail, even though live data is small
refquota No — referenced (live) data only Pool free space is silently consumed instead

If your root dataset uses quota, orphaned snapshots will eventually take the machine down. zfs-backup doctor flags any dataset whose snapshots consume more than half its quota.

Requirements

  • Linux with ZFS filesystem
  • syncoid (from sanoid package)
  • Root privileges or ZFS delegation configured
  • External drive with encrypted ZFS pool (for backups)

Menu Options

Option Description
Back Up Now Run an incremental backup of the datasets in scope
Pull Backup From Remote Pull backup from a remote host via SSH
Push Backup to Remote Push local snapshots to a remote backup server
Restore Files Browse snapshots and restore individual files
Backup Scope Choose which datasets are backed up - anything else is never touched
Backup Health Check Find orphaned snapshots and datasets whose quota is filling with snapshots
Pool Information View pool structure, health, datasets, and snapshots
Pool Maintenance Start/stop scrubs, monitor pool health
Recover Failed Backup Fix broken sync state after interruption
Unmount Backup Disk Safely export pool and power off USB drive
Prepare Backup Device Create new encrypted ZFS pool on external drive
Force Full Backup Reset backup when incremental chain is broken (typed confirmation)

Keyboard Shortcuts

Navigation

Key Action
↑/k ↓/j Navigate
Enter Select
Esc Go back
q Quit

Scrollable Views (Pool Info, Maintenance, Results)

Key Action
j/k Scroll line
Ctrl+u/d Page up/down
g/G Top/bottom

Restore Mode

Key Action
Tab or h/l Switch panels
Space Toggle selection
y Copy selected files
/ Search
m Create directory

See Full Keyboard Reference.

Documentation

Architecture

zfs-backup/
├── main.go       # Bubble Tea TUI and main application logic
├── zfs.go        # ZFS operations (backup, prepare, unmount)
├── state.go      # Backup state management for resume
├── restore.go    # Restore mode with dual-panel explorer
├── flake.nix     # Nix flake configuration
└── docs/         # MkDocs documentation

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

See Contributing Guide.

License

MIT License - see LICENSE file for details.


Made with <3 by Kartoza | Donate! | GitHub

About

Beautiful TUI for managing ZFS backups with Bubble Tea

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages