A high-performance, lightweight, read-only web explorer and audit tool for OpenZFS, Btrfs & POSIX filesystem snapshots.
Instead of browsing snapshots one by one or mounting snapshot directories manually over SSH, Universal Snapshot Explorer visualizes the complete version history of all files and folders across all available snapshots simultaneously.
- π Multi-Snapshot Timeline Bar: Each file and folder features an interactive, color-coded timeline bar indicating modifications, creations, deletions, and static periods across all snapshots at a single glance. The timeline is built with accessible, colorblind-friendly SVG pill designs, and the criteria for what constitutes a "change" (e.g., Size, Permissions, UID/GID, Mtime) is fully configurable.
- ποΈ Pluggable Multi-Filesystem Architecture: Native support for OpenZFS datasets (
.zfs/snapshot) and Btrfs subvolumes (including Snapper metadata layouts). - π Boundary & Mount Discovery: Automatically detects nested mount points and sub-datasets via
/proc/mounts, rendering dedicated per-dataset snapshot timelines in table rows and breadcrumbs. - π€ ZFS CLI Integration & Auto-Discovery: Seamlessly discovers all active datasets across your ZFS pools with
/dev/zfspassthrough and retrieves exact snapshot creation timestamps directly from ZFS metadata. - π¦ Checkbox Multi-Selection & Streaming ZIP Download: Select multiple files or folders across any snapshot and download them instantly as an on-the-fly streaming ZIP archive without creating temporary files on disk.
- π‘οΈ POSIX ACL & Permissions Enforcement: Fully replicates the kernel's access-control logic. If the user doesn't have read access to a file, they can't see or download it. Operates via HTTP headers (like TrueNAS auth proxies) and correctly evaluates inherited group mask and traversal permissions.
- π Instant Audit & Advanced Column Filters:
- Column Filters: Powerful search strategies per column, including size ranges (
5mb..10mb), octal mode masks (700,g:x), relative dates (today), and wildcards. - "Changed only" (
historyicon): Instantly filter out static files to spot what was modified, added, or deleted between snapshots. - "Missing files" (
ghosticon): Toggle visibility of files that do not exist in the current snapshot. - "Hidden files" (
eye-officon): Toggle visibility of dotfiles (.*).
- Column Filters: Powerful search strategies per column, including size ranges (
- βοΈ Modular N-Way File Differ: A unified diffing engine designed to compare files across multiple snapshots simultaneously (currently equipped with a TextDiffer plugin for side-by-side 2-way text comparisons).
- β¨οΈ Full Keyboard Navigation:
β/β: Navigate through rows.β/β: Expand/collapse folders or navigate to parent directories.Enter: Open selected folder or download file.i: Open deep version details view.Ctrl + L/Cmd + L: Jump to breadcrumb path bar with live typeahead.h/?: Open keyboard shortcuts cheat sheet.
- π§ Clean URL Structure (
/-/Delimiter): Uses the proven GitLab/GitHub delimiter pattern (/list/pool/dataset/-/sub/folder) for unambiguous navigation in deeply nested dataset pools. - π Deep File Details & Change History: Compare file sizes, MIME types, POSIX permissions, ownership (UID/GID resolved via host
/etc/passwd), and timestamps across all snapshot versions. - π Safe & Read-Only: Operates completely read-only (
:ro). Zero database, zero storage overhead, and zero risk of accidental data modification. - π Modern Dark & Light Theming: Seamless system theme detection (
prefers-color-scheme) with an instant toggle and Lucide vector icons. - π Multi-Language Support (i18n): Native support for English and German with automatic browser language detection.
- Self-Service File Recovery for Teams & Homelabs: Let users easily locate and download previous versions of their documents without needing SSH access or bothering system administrators.
- Forensic Audit & Incident Response: Instantly pinpoint the exact snapshot where a ransomware attack, faulty migration script, or unintended deletion took place.
- Version History for Large Assets (Video, 3D, Audio, CAD): A "Git-like" visual history browser for large binary assets where traditional version control systems struggle.
Run the container with /dev/zfs device passthrough and mount the host filesystem root to /host with rslave propagation for dynamic ZFS snapshot automounts:
services:
universal-snapshot-explorer:
image: ghcr.io/nicolasgoeddel/universal-snapshot-explorer:latest
container_name: universal-snapshot-explorer
restart: unless-stopped
ports:
- "8090:8080"
# Privileged flags (privileged, security_opt, cap_add, devices) are ONLY required if you
# want to query ZFS metadata via ZFS CLI commands (ZfsCliSnapshotProvider).
# You can completely omit these if you run in unprivileged User-Space fallback mode
# (FilesystemSnapshotProvider), which discovers snapshots by scanning .zfs/snapshot dirs.
privileged: true
security_opt:
- apparmor:unconfined
cap_add:
- SYS_ADMIN
devices:
- /dev/zfs:/dev/zfs
volumes:
# Read-only access to host root. 'rslave' propagation is needed to dynamically propagate
# ZFS auto-mounted snapshots from host to container. Use simple ':ro' for static mounts.
- /:/host:ro,rslave
# Application configuration file
- ./config.yaml:/app/config.yaml:ro
environment:
- PYTHONUNBUFFERED=1# Global OpenZFS Auto-Discovery Configuration
zfs:
# Automatically discover all mounted ZFS datasets on the host (scanning for .zfs/snapshot directories)
auto_discover: true
# Prefix where the host filesystem root is mounted in the container
mount_prefix: "/host"
# Glob patterns for datasets to ignore during auto-discovery
exclude_datasets:
- "*/.system*"
- "*/ix-applications*"
- "*/docker*"
- "*/custom-apps*"
# Default host user/group resolution files to map UIDs/GIDs to usernames/groupnames.
# If omitted (or set to null), no UID/GID translation takes place, and raw numbers are displayed.
default_user_map: "/host/etc/passwd"
default_group_map: "/host/etc/group"
# Regex patterns to parse timestamps from snapshot directory names in fallback/filesystem mode.
# Supports datetime directives (like %Y, %m, %d, %H, %M, %S) or wildcards (like {year}, {month}).
# Necessary for sorting snapshots chronologically if ZFS CLI metadata is unavailable.
snapshot_patterns:
- "auto-%Y-%m-%d-%H%M%S"
- "periodic-%Y-%m-%d-%H%M%S"
# Global Btrfs & Snapper Auto-Discovery Configuration
btrfs:
# Automatically discover all active Btrfs subvolumes containing .snapshots directories
auto_discover: true
# Prefix where the host filesystem root is mounted in the container
mount_prefix: "/host"
# Glob patterns for Btrfs paths to exclude from auto-discovery
exclude_paths:
- "/var/lib/docker/*"
- "/var/lib/containers/*"
- "*/tmp*"
default_user_map: "/host/etc/passwd"
default_group_map: "/host/etc/group"
# Optional: Manually define custom roots, sub-paths, or non-discovered backup partitions
roots:
# Example 1: ZFS backup dataset with nested sub-path
Backup Rocky:
# Absolute path to the dataset root directory (must contain the .zfs folder)
root_path: /host/mnt/data/backups
# Subfolder inside the dataset root. Useful if the dataset does daily snapshots at
# the root level but contains nested home folders or root partition mirrors (like 'Rocky')
sub_path: Rocky
# Explicit filesystem type: "zfs", "btrfs", or "generic"
filesystem_type: zfs
# Relative path (e.g. 'etc/passwd'): dynamically resolved from the currently active snapshot!
# Absolute path (e.g. '/host/etc/passwd'): statically resolved from the host filesystem.
# If omitted, falls back to raw numerical UIDs/GIDs for files inside this root.
user_map: etc/passwd
group_map: etc/group
# Snapshot patterns specifically for this root
snapshot_patterns:
- "rocky-backup-%Y-%m-%d"
# Example 2: Btrfs root volume with Snapper snapshot layout
System Root:
root_path: /host
sub_path: ""
filesystem_type: btrfs
user_map: etc/passwd
group_map: etc/group
# Log verbosity level. Supported values: debug, info, warning, error, critical
loglevel: infoTip
For a detailed breakdown of all configuration parameters, filesystem providers, path resolution mechanics (e.g. btrbk setup, custom snapshot directories), and dynamic UID/GID mappings, see the Configuration & Architecture Guide.
- Python 3.14+
- uv
-
Install dependencies:
uv sync
-
Start development server (with hot-reload):
uv run use --reload --port 8000 --config-file "config.yaml" -
Open browser: http://127.0.0.1:8000
# Run Python linters, type checker, and formatters
uv run ruff check src tests
uv run basedpyright src
uv run ruff format --check src tests
# Run JavaScript linter & formatter (Biome)
biome check src/goeddel/use/static/js
# Automatically apply safe fixes and formatting:
biome check --write src/goeddel/use/static/js
# Run unit & integration tests
PYTHONPATH=src uv run python -m unittest discover -s tests -p "test_*.py" -v
# Run tests with code coverage tracking
PYTHONPATH=src uv run coverage run -m unittest discover -s tests -p "test_*.py" -v
# Display text coverage report
PYTHONPATH=src uv run coverage report -m
# Generate interactive HTML coverage report (opens in htmlcov/index.html)
PYTHONPATH=src uv run coverage htmlSee TODO.md for the detailed roadmap and RELEASES.md for the version changelog.
For developers and contributors, the system architecture and internal design decisions are documented in ARCHITECTURE.md.
AGPLv3 (See LICENSE)




