ArkVault: A BorgBackup GUI Where the Drive Rebuilds Your Linux Box

Posted
July 11, 2026
By
Jacob Lloyd — written with AI assistance, post-project
Read time
8 min read

In plain terms: A free backup program for Linux computers with a simple point-and-click window. It saves an encrypted copy of your important files to an external drive, and the drive itself carries a step-by-step recovery guide — so if your computer dies, a brand-new machine can be rebuilt straight from the drive.

Plug a backup drive into a fresh Linux install — nothing configured, nothing on it — and get more than your files back. ArkVault writes a guided restore kit onto the drive next to the encrypted backup, so the drive itself knows how to rebuild the machine: dotfiles, SSH keys, launcher symlinks, systemd units, the works.

TL;DR

  • What it is: a GTK4 GUI (plus a full headless CLI) around BorgBackup that writes an install-map manifest and a copy of itself onto every backup drive.
  • What it costs: free, MIT licensed. Source zip below. No account, no cloud.
  • What you need: Linux with GTK4/libadwaita (stock on Fedora/GNOME, one apt line on Debian/Ubuntu), a spare drive, and an evening to edit the catalog of what's worth capturing.
  • What you end up with: an encrypted, deduplicated backup plus a restore wizard that runs off the drive on a machine with nothing installed. I ran the restore drill for real, not just the happy path.

What you end up with

Tool first, theory later. These are from a sandboxed run with dummy data, not my real machine's file list.

ArkVault main window: backup target picker, four profile toggles with live size estimates, a lock badge on the Settings and Dotfiles profile, and a Back up everything important button

Four profiles, live size estimates, a lock badge wherever a profile touches secret-flagged items like SSH keys. One button backs up everything you've toggled on.

ArkVault restore wizard showing install-map items grouped by category — Projects and Settings — with checkboxes, a lock icon on the ssh item, and a Set options button

This is the point of the whole tool: the restore wizard reads the install-map off the drive and shows exactly what got captured, grouped and checkable, lock icon on anything sensitive. No mystery blob.

ArkVault Drag and Drop Backup window with a named collection, a drop zone for files and folders, and Add files or Add folder buttons

There's also a drag-and-drop mode for one-off collections that don't belong in the main catalog.

MetricValue
Code~7,100 lines of Python across 48 files
Pip dependenciesZero — GTK comes from the system, requirements.txt is intentionally empty
Test suite82/82 checks pass, no pytest needed
Zip size108 KB, 53 entries (Borg's binary isn't bundled — the installer fetches it)
Restore drill result8/8 items landed correctly in a second, fresh $HOME
LicenseMIT, free

What Borg actually buys you

ArkVault isn't its own backup engine. It's a front end around BorgBackup, which does the hard parts:

  • Encryption: repokey-blake2. The key lives inside the repo, protected by your passphrase. Whoever steals the drive gets nothing.
  • Deduplication: content-defined chunking, so ten snapshots of a slowly-changing home directory don't cost ten times the space.
  • Compression: zstd at level 6. Decent squeeze without slowing the backup to a crawl.
  • Retention: borg prune keeps 7 daily, 4 weekly, 6 monthly by default (configurable), so old snapshots age out instead of eating the drive.

ArkVault adds the part Borg doesn't care about: which files matter, what permissions they need, and what has to happen after the files land for the machine to actually work again.

Why an immutable distro forced a different design

I built this for a Bazzite box — immutable, atomic Fedora, read-only root. That constraint shaped the whole tool:

  • Everything installs under ~/.local. Nothing touches /.
  • The venv is built with --system-site-packages so GTK4/PyGObject comes from the host instead of compiling bindings against a read-only base.
  • pip install borgbackup flatly doesn't work here — no liblz4 headers, no matching wheels — which is the real reason the installer downloads the official upstream standalone Borg binary, a PyInstaller build with FUSE bundled in.
  • No sudo anywhere. The one operation that needs root — formatting a drive — goes through a polkit/pkexec prompt.

The actual idea: the drive rebuilds the machine

Ordinary backup tools give you files back. You still have to remember where everything went and which systemd units to re-enable. ArkVault writes that knowledge onto the drive, every backup:

  • arkvault-repo/ — the encrypted Borg repository.
  • ArkVault-App/ — a self-bundled copy of ArkVault, source and installer, copied atomically (tmp dir, then rename) so an interrupted copy never leaves a half-app on the drive.
  • arkvault-install-map.json plus RESTORE-README.md — a manifest of everything captured and a plain-text walkthrough you can read with zero tooling.

The install-map records that a file is secret, never its contents. The drive knows what it's carrying without spilling any of it.

What a backup run actually does

A backup run is a straight line: discover what the catalog matches (missing paths get skipped), optionally quiesce write-heavy services so live databases land consistent, borg create, borg prune, then write the restore kit to the drive.

The paranoid parts

This is the code that took the time:

  • The format guard refuses the system disk. Formatting the wrong drive is the classic backup-tool disaster. ArkVault resolves LUKS/LVM device-mapper chains down to physical disks by walking /sys/class/block/*/slaves — an encrypted root's mapper name looks nothing like the underlying disk, so naive name checks miss it. If it can't enumerate the system disks at all, it fails closed and refuses to format anything. You still type the exact device name to confirm.
  • Path containment on restore. A malformed or tampered install-map can't write outside the target home: symlinked ancestors get resolved, the leaf symlink is deliberately not followed, and redeploy targets that try to escape home are refused.
  • Secret hygiene in logs. The passphrase and anything registered as secret get scrubbed by literal match plus regex backstops for patterns like apiKey: and Bearer.
  • The recovery sheet. First backup shows a passphrase sheet with non-selectable text — no accidental clipboard copy — and the dismiss button stays disabled until you tick "I have saved my passphrase." The sheet never gets written to the drive. Lose the passphrase, lose the backup. That's what real encryption means.
  • FAT32 is refused as a repo target — its 4 GB file cap breaks Borg outright. exFAT is allowed with a warning, since Borg stores Unix metadata internally anyway.
  • Empty archives are refused. If every source path vanished (drive unmounted, catalog typo), ArkVault refuses to write an empty archive that would look like a success.
  • Verifying is on you, whenever you want. borg check runs from the UI or CLI as a real integrity check, and "Browse snapshot" mounts an archive read-only over FUSE so you can poke through it before you trust it.

Setting it up

You need GTK4/libadwaita PyGObject bindings, udisks2, and polkit. Stock on Fedora/GNOME family; one line on Debian/Ubuntu:

sudo apt install python3-gi gir1.2-gtk-4.0 gir1.2-adw-1

Then the installer, which is idempotent — safe to re-run:

bash install.sh

That copies the app to ~/.local/share/arkvault, builds the --system-site-packages venv, downloads the official Borg standalone binary, and drops ~/.local/bin/arkvault plus a desktop entry. Then:

arkvault probe

Everything should say OK. Bare arkvault launches the GUI; the same core also drives a headless CLI:

arkvault probe|backup|restore|list|check

The one step that actually matters: edit the catalog. The shipped one is a generic example — core/discovery.py, profiles.py, core/quiesce.py, core/containers.py, and core/installmap.py all have marked "EDIT ME" blocks. A curated list of what a fresh install can't hand back is the whole point, and nobody can write yours for you.

Run the first backup, save the recovery sheet somewhere that isn't the backup drive, and click "Copy app to drive." For unattended runs there's a systemd user timer template in README-SETUP; it reads the passphrase from the keyring or ARKVAULT_PASSPHRASE.

Proving it actually works

A backup you've never test-restored is a hope, not a backup. So, against a fake $HOME:

  1. Unzipped the source, ran install.sh — real Borg download, 27.9 MB.
  2. arkvault probe: all OK.
  3. arkvault backup of 3 example profiles into a scratch drive directory: 8 items in, repo initialized with repokey-blake2, install-map + RESTORE-README + self-bundle written.
  4. arkvault list, then arkvault check: passed.
  5. arkvault restore into a second fresh home: all 8 items landed at the right paths, manual checklist printed for the rest.

The dependency-free test suite goes 82/82 on the exact tree in the zip.

Gotchas

  • The zip fixes a bug the original install script had. Borg's GitHub releases ship a GPG .asc signature but no .sha256 sidecar, so the installer's checksum fetch 404'd and set -e killed the install before the script's own fallback could run. Fixed here, plus an optional ARKVAULT_BORG_SHA256 env var to pin a known-good hash. My own box never hit it — my Borg binary already existed, so the download branch simply never ran.
  • FAT32 will quietly ruin your week. ArkVault detects and refuses it, but plenty of USB drives ship that way out of the box.
  • A crashed run leaves a stale repo lock. borg break-lock clears it (there's a button in the GUI), and BORG_LOCK_WAIT=120 makes overlapping runs wait instead of failing instantly.
  • Live SQLite in WAL mode needs the db, wal, and shm files captured together, or the service stopped first. That's why the quiesce step exists — its restart is in a finally block, so services come back even if the backup dies mid-run.
  • Restoring into a different username works, because every destination is recorded relative to home. Ownership that can't be mapped onto the new user lands on the manual checklist instead of getting silently skipped.
  • No GNOME keyring (headless box, CI)? It degrades to an in-memory passphrase plus a prompt instead of failing.
  • The boring bug: python -m arkvault backup ... used to silently no-op — the GUI's argument parser ate the subcommand and exited 0. __main__.py now dispatches CLI subcommands explicitly. Scary bugs announce themselves; the dangerous ones exit clean and do nothing.
  • The shipped catalog is a blank example on purpose. The one I actually run lists exactly where my important stuff lives, which is precisely what shouldn't ship in a public zip. You get a clean Projects/Settings example with a worked redeploy sample instead — same structure, none of my paths.

Downloads

Free for personal use. If it saves you an afternoon, the coffee button's nearby.


← More Tools & Downloads