Contents

I Wanted Time Machine for Linux, So I Built a Web UI for Btrfs

This article is also available in 日本語.

I built btrfs-timeline, a tool that lets you browse and restore previous versions of your files from btrfs snapshots, right from your browser. The goal is to make “what did this file look like last month?” as easy to answer as it is with Time Machine on a Mac.

https://raw.githubusercontent.com/akivajp/btrfs-timeline/main/docs/screenshots/screenshot-history-en.png

Why I built it

The snapshots are there, but getting a file back is hard

  • I run a few self-built servers, and all of them use btrfs RAID
    • btrfs is very flexible about RAID layouts and makes good use of disks of different sizes, so I have grown quite fond of it
  • I also take automatic snapshots with snapper and the like, so every previous version of every file is already sitting on my disks
  • But when I actually need to recover a single file I deleted or overwrote by mistake, I have to:
    • know where the snapshots live,
    • guess which snapshot is old enough,
    • and compare files by hand on the command line.
  • It works, but honestly, it is an expert-only chore
    • And recovering files like this is the whole reason for taking snapshots in the first place

I looked for existing tools, but…

Before writing anything, I surveyed what was already out there.

ToolWhat it doesWhy it did not fit
httmExcellent interactive file history for ZFS/btrfsCLI/TUI only
TimeshiftSystem-wide snapshots and restoreBuilt for rolling back the whole system, not for walking back through one file
Btrfs Assistant, Snapper GUISnapshot managementDesktop apps; not per-file history
Samba vfs_shadow_copy2“Previous Versions” in Windows ExplorerRequires a Windows client
Rockstor, OpenMediaVaultNAS web UIs with btrfs supportNAS-only distributions; rollback is per share, not per file
CockpitCreating btrfs filesystems and subvolumesNo snapshot browsing
  • httm comes closest in features and is very well made, but it lives in the terminal
  • Searching GitHub for btrfs web UIs turned up mostly hobby experiments and projects that had not been updated in years
  • In short, nothing let me open a browser, point at a path, and walk back through time — so I decided to build it

What it does

  • It finds your btrfs snapshots and lists the previous versions of any file you point it at
  • You can preview each version, diff it against the current file, and restore it with one click
  • There are three ways to use it:
    • CLI (btrfs-timeline history and friends)
    • Standalone web UI (started with btrfs-timeline serve)
    • Cockpit module (if you already use Cockpit, the same screen opens inside it)
  • It supports the snapper layout (.snapshots/<number>/snapshot) as well as the flat .snapshots/<name> layout used by btrbk, Timeshift and hand-rolled setups

Trying it out

Installation

$ pipx install 'btrfs-timeline[web]'   # with the web UI
$ pipx install btrfs-timeline          # CLI only, no dependencies
  • Requires Python 3.9+ and Linux
  • Browsing history does not even need btrfs-progs

Viewing history from the CLI

$ btrfs-timeline history ~/.gitconfig
/home/user/.gitconfig
  # FIRST SEEN           LAST SEEN                  SIZE   SNAPS STATE
  1 2024-10-02 02:00:08  2025-01-01 00:00:00           -       3 (does not exist)
  2 2025-12-01 00:00:08  2026-03-01 00:00:00       268 B       4 ok
  3 2026-04-01 00:00:00  2026-09-23 01:00:00       297 B      28 ok
  4 -                    -                         297 B       - live
  • Thirty-five snapshots collapse into three meaningful versions, plus the stretch before the file existed — four rows in total
  • This is the heart of the tool; more on it below

Using the web UI

$ btrfs-timeline serve                       # http://127.0.0.1:8088/
$ btrfs-timeline serve --root ~/Documents    # only expose this directory
$ btrfs-timeline serve --read-only           # browsing only; restore disabled
  • Browse directories on the left; click a file and its versions appear on the right
  • Click a directory and pick a version, and the list on the left switches to what the directory contained at that point in time
    • Files deleted since then show up there with a strikethrough. They no longer exist on the live filesystem, so this is how you find a file you have lost
  • The preview pane doubles as a diff view

Restoring

$ btrfs-timeline restore ~/notes.md --index 2    # restore a given version
$ btrfs-timeline restore ~/notes.md --dry-run    # just show what would happen
  • In the web UI it is one click — but it always shows you where it will write and what it will write before asking for confirmation

Things I cared about

No root needed to browse history

  • The obvious way to find snapshots is btrfs subvolume list, but that requires root
  • The files inside snapshots, on the other hand, are readable with ordinary permissions
  • So the tool discovers snapshots using only /proc/self/mountinfo and a directory walk
    • As a result, browsing history requires no root, and the web server never has to run as root

Identical versions are merged

  • btrfs is copy-on-write, so an unchanged file appears in every single snapshot
    • On my machine, one file showed up in 35 snapshots, and all of them were the same version
  • A list of 35 identical rows tells you nothing, so versions with the same mtime and size are merged into one
  • Periods when the file did not exist are kept as their own entries
    • Otherwise, a file that was deleted and later recreated would look as if its history had never been interrupted

Restoring never destroys the current file

  • The worst accident a history tool can cause is wrecking the current contents while trying to bring back an old version
  • So by default nothing is overwritten. The restored file lands next to the original under a name like notes.20260401T000008.md
    • Overwriting requires an explicit --in-place, and even then the current contents are saved aside first
  • Restores use a reflink (btrfs extent sharing) instead of a copy, so they finish instantly regardless of file size and take no extra space

The web UI is not exposed by accident

  • By default it only listens on loopback (127.0.0.1)
  • On any other address it refuses to start unless you pass --auth USER:PASSWORD
    • Anyone who can reach it could read your files and even overwrite them, so this should never happen by accident

Cockpit gets the very same screen

  • If you already use Cockpit, you can open the same screen inside it

    $ btrfs-timeline cockpit install
    
  • A Cockpit module is just static files; it cannot have a server side of its own

    • So the core of the tool is a CLI that answers with --json, and both the web UI and the Cockpit module are built on that same output
    • The screen code is shared, and the only file that differs is transport.js, which fetches the data (HTTP for the web UI, cockpit.spawn calling the CLI for Cockpit)

Bonus: dashboard and maintenance

  • Beyond file history, there is a device dashboard for NAS-style setups

https://raw.githubusercontent.com/akivajp/btrfs-timeline/main/docs/screenshots/screenshot-devices-en.png

  • It shows each filesystem’s devices, RAID profiles, per-device error counters, device models and temperatures (again, no root needed)
  • Scrub, balance, and adding, removing or replacing devices are available from the CLI
    • Every operation declares its risk level (safe / changes state / dangerous) and shows the exact command before asking for confirmation
    • Operations that can lose data if they go wrong, such as replacing a device, cannot run until you type the target device’s name (the same idea as typing a repository’s name to delete it on GitHub)

Wrapping up

  • If you take automatic btrfs snapshots, the old versions are already on your disks. What was missing was an easy way to walk back through them
  • btrfs-timeline lets you walk back through a file’s history from a browser (or the CLI, or Cockpit) and restore it without touching the current file
  • Browsing history needs no root

It is still in early development, but if you use btrfs, please give it a try. Bug reports and feature requests are welcome on GitHub Issues.