Status: alpha — under active development. Thur has not had a stable release. On-disk formats, configuration keys, and the SCSI / NVMe surface may change without notice or migration path. Not recommended for production use.
Thur is two sibling cloud-backed storage targets built on a shared Rust codebase. Each presents an ordinary storage device to the host, but the data lives in cloud object storage — local disk holds only a warm, refcount-evicted cache in front of it. The capacity a host can address is set by the cloud bucket, not the local disk: a modest cache machine can front a dataset many times its own size.
Stored data is deduplicated in a shared content-addressed chunk pool. Every chunk is keyed by its BLAKE3 hash, with no central index or database, so identical bytes from any source — across every volume and cartridge on a backend — are stored exactly once.
The two products share that chunk pool, the dedup layer, and the cloud-tiering machinery, but they present different device types over different host protocols, and are packaged and deployed independently:
- Thur VTL — a Virtual Tape Library that presents a spec-conformant SMC-3 medium changer and SSC-4 LTO-8 drive surface over iSCSI. From the backup software's perspective it is an ordinary tape library — no proprietary agent required.
- Thur VSA — a Virtual Storage Appliance: a block-storage target that serves thin-provisioned SBC-3 LUNs over iSCSI or NVMe/TCP. It behaves as a cloud-backed virtual disk for VMware, Hyper-V, and Linux hosts.
Both products can live co-resident on a single host; they use disjoint system users, data directories, conffiles, systemd unit names, and admin sockets. Cloud storage (S3, GCS, or Azure) is, in all cases, the durable source of truth.
Thur is experimental backup and storage software. It is provided "as is", without any warranty of any kind. There is no guarantee of data integrity, reliability, or fitness for any purpose.
You are solely responsible for verifying your backups and maintaining independent copies of critical data. The authors and contributors accept no responsibility or liability for data loss, corruption, or any damages resulting from the use of this software. Use at your own risk.
The following capabilities are shared across both products:
- Content-addressed dedup — BLAKE3-hashed chunks stored once per backend pool; cross-volume / cross-cartridge.
- Cloud tiering — S3-compatible (AWS S3, MinIO, Wasabi, …), Google Cloud Storage, Azure Blob. Disk is a warm cache with a per-backend budget and write backpressure when the budget is hit.
- Two-layer compression (zstd / lz4); parallel cloud up/downloads.
- CHAP authentication for iSCSI; TLS-PSK for NVMe/TCP (VSA).
- Append-only, BLAKE3-chained audit log; Prometheus metrics + OTLP.
- Optional at-rest encryption under a pluggable DEK keystore.
Thur VTL additionally provides:
- Spec-conformant SMC-3 medium changer + SSC-4 LTO-8 drives over iSCSI; configurable topology (caps 65535 slots / 65535 mail slots / 255 drives).
- Virtual cartridges with full sequential-access semantics, WORM, cloud-native legal hold, the LTFS two-partition layout, and LTO Application-Managed Encryption.
- Cross-region disaster recovery; cartridge migration and archive between cloud backends.
Thur VSA additionally provides:
- SBC-3 block target over iSCSI, or the NVM Command Set over NVMe/TCP.
- Thin-provisioned per-volume LUNs, 4 KiB sectors, sparse page table, write-back page cache.
- VAAI / NVMe data-path primitives and persistent reservations.
- Linux (tested on Ubuntu 26.04).
- Building from source: a C compiler, OpenSSL headers, pkg-config, and Rust 1.92+ (2024 edition).
- Integration tests:
open-iscsi,sg3-utils,mtx,mt-st,libiscsi-bin,lsscsi. - A cloud storage account (S3 / GCS / Azure) for production; the
localbackend needs none.
The shortest path is the https://thur.metebalci.com apt / yum repository — one line on any supported distro:
curl -fsSL https://thur.metebalci.com/install.sh | sudo bashThis wires up the stable channel (tagged releases without a
pre-release suffix; includes pre-1.0 builds). Set CHANNEL=unstable
to install from the pre-release channel that holds alpha / beta /
rc tags. The script writes the right sources.list.d or
yum.repos.d entry and installs the signing public key alongside it.
The fingerprint is documented in
docs/RELEASING.md — verify it against the key
the script imports.
For air-gapped installs, offline staging, or anyone who'd rather not
delegate the install ceremony to a piped shell script, the packages
can also be downloaded directly from
GitHub Releases. Each
tagged release ships separate .deb / .rpm packages per product —
thurvtl and thurvsa. One .deb covers Debian 12/13 + Ubuntu
24.04/26.04; one .rpm covers RHEL 9/10 + Rocky/Alma + SLES 15 SP6+/16
- openSUSE Leap. Only the
.debon Ubuntu 26.04 is regularly tested; other targets are best-effort. Products co-exist on one host with disjoint users, data dirs, conffiles, unit names, and admin sockets.
Packages install to /usr/bin/, drop a systemd unit, and lay down a
minimal starter conffile (/etc/thurvtl/thurvtl.yaml /
/etc/thurvsa/thurvsa.yaml). They do not auto-start the daemon —
it needs configuration first. /var/lib/{thurvtl,thurvsa}/ (operator
data) is never touched on uninstall.
Most CLI commands are daemon-routed — they reach the running
daemon through its admin socket (/run/thurvtl/admin.sock /
/run/thurvsa/admin.sock, mode 0660, owned by the product's system
user). To run those as an ordinary user, add yourself to that
product's group — each product has its own:
sudo usermod -aG thurvtl $USER # log out and back in to apply
sudo usermod -aG thurvsa $USER # ...and thurvsa, on a co-resident hostAlternatively, invoke the CLI as the daemon user per command —
sudo -u thurvtl thurvtl .... Pure-local commands (config defaults)
use no socket and need neither.
Every release artifact ships a detached .asc GPG signature — verify
it before installing. Key fingerprint and the build / signing process
are in docs/RELEASING.md.
Other install paths:
- Static binary tarball — for distributions outside the
.deb/.rpmmatrix; carries the binaries, a reference yaml, the systemd unit, shell completions, man pages, and an install-focused README. - From source —
cargo build --release; binaries land intarget/release/. Not recommended for production.
The one required key in each conffile is data_dir. Add at least one
cloud backend under cloud.backends:. The config defaults command
prints the full annotated reference — every key documented with its
default value and a description — which you can redirect straight to a
starter file:
thurvtl config defaults > thurvtl.yaml
thurvsa config defaults > thurvsa.yamlCloud credentials are wired per-backend (auth: blocks) or via the
default credential chain / daemon env file; the reference is
docs/AUTH.md. Every config file and YAML key is
catalogued in docs/CONFIGURATION.md. Both
the daemon and CLI resolve --config PATH first, otherwise
/etc/<product>/<product>.yaml.
Thur VTL also needs a chassis declaration. Add a library: block to
your thurvtl.yaml — every field is required:
library:
num_slots: 40 # storage slots; raise/lower by editing this and restarting
num_drives: 3 # tape drives
lto_generation: 8 # 7 or 8 (LTO-8 only is supported today)The daemon materializes <data_dir>/library/library.json from this
block on first start (minting a stable chassis serial + SMC element
bases). On subsequent starts it diffs the YAML against the persisted
declaration and reconciles: grow operations always succeed; shrink
operations refuse if any cartridge or loaded drive would be orphaned.
thurvtl library bounds (against a running daemon) shows the
safe-shrink envelope for the current inventory. No imperative chassis
mutation — edit the YAML and restart the daemon.
Add cartridges via thurvtl cartridge create once the daemon is up.
sudo systemctl enable --now thurvtld # or thurvsad
sudo systemctl status thurvtld
sudo journalctl -u thurvtld -fEach daemon runs an iSCSI target (port 3260) and an HTTP metrics
server (port 9090) in a single process. For co-resident installs,
override one of each port in YAML. Persist systemd customizations
through sudo systemctl edit <unit> so package upgrades don't
clobber them.
Once the daemon is running, connect from any iSCSI initiator in the usual way. The library and drive LUNs appear as standard kernel devices:
sudo iscsiadm -m discovery -t sendtargets -p <target_ip>:3260
sudo iscsiadm -m node -T iqn.2025-10.com.metebalci:thurvtl \
-p <target_ip>:3260 --login
lsscsi -g
# [7:0:0:0] mediumx MB THUR VTL NVL8 /dev/sch0
# [7:0:0:1] tape MB Ultrium 8-SCSI NVL8 /dev/st0On Windows, use the built-in iSCSI Initiator (Control Panel) — add the portal, connect, and the devices appear under Tape drives and Medium Changers.
The host kernel sees a standard tape library — back up with tar,
control the drive with mt, drive the changer with mtx:
sudo tar -cvf /dev/nst0 /path/to/backup # write
sudo tar -xvf /dev/nst0 # restore
sudo mt -f /dev/st0 status # drive status
sudo mtx -f /dev/sch0 status # library status
sudo mtx -f /dev/sch0 load 1 0 # load slot 1 -> drive 0thurvtl manages the library without an iSCSI initiator. This is
useful for provisioning cartridges, inspecting inventory, and running
analytics before or after a backup session:
thurvtl cartridge create TAPE001 # new cartridge, first free slot
thurvtl cartridge list # --json for automation
thurvtl changer inventory
thurvtl changer load 1 0
thurvtl system stats # dedup analyticsCartridge lifecycle — creation flags, WORM, legal hold, at-rest
encryption — is in docs/CARTRIDGE.md.
thurvsa talks to the running daemon over its admin socket
(the daemon must be up):
thurvsa volume create myvol --size 100G
thurvsa volume listVSA serves each volume as a block LUN. The default transport is
iSCSI; set transport: nvmetcp in thurvsa.yaml to serve NVMe/TCP
instead (one listener binds, not both).
# iSCSI (port 3260)
sudo iscsiadm -m discovery -t sendtargets -p <target_ip>:3260
sudo iscsiadm -m node -T iqn.2025-10.com.metebalci:thurvsa \
-p <target_ip>:3260 --login
# NVMe/TCP (port 4420)
sudo nvme connect -t tcp -a <target_ip> -s 4420 \
-n nqn.2025-10.com.metebalci:thurvsaThe host sees a thin-provisioned block device — partition, format,
and mount it like any disk. The NVMe/TCP transport design (handshake,
R2T flow, auth) is in docs/NVMETCP.md.
Both products store data as content-addressed chunks in a per-backend
pool. The backend type determines where those chunks live; configure
backends under cloud.backends: in the conffile, giving each entry a
name, a type (s3 / gcs / azure / local), and its
per-cloud knobs:
cloud:
backends:
primary:
type: s3
bucket: thur-data
prefix: "data/"
region: us-east-1
archive:
type: gcs
bucket: thur-cold
prefix: "data/"
project_id: my-projectThe local backend is filesystem-only — no credentials, no cloud —
ideal for testing:
cloud:
backends:
primary:
type: local
root_dir: "./.thur/local-backend"On startup the daemon validates each cloud backend's credentials,
bucket existence, and read/write/delete permissions, and refuses to
start on failure. Validate ahead of time, without starting the
daemon, with thurvtl system cloud check.
- Credentials —
auth:blocks, default chains, the daemon env file, multi-provider layouts:docs/AUTH.md. - S3-compatible provider matrix — Backblaze B2, Wasabi, Hetzner,
OVHcloud, …:
docs/S3_BACKENDS.md. - WORM, legal hold, at-rest encryption (incl. provider bucket
setup):
docs/CARTRIDGE.md. - Cross-region DR, cartridge migration / archive —
docs/SPEC.md.
Each daemon exposes HTTP on port 9090 for health and observability
probes. The /metrics endpoint serves Prometheus-formatted metrics
and is always wired — there is no on/off switch separate from the HTTP
listener itself:
curl http://localhost:9090/health # liveness probe
curl http://localhost:9090/metrics # Prometheus
curl http://localhost:9090/sessions # iSCSI sessions
curl http://localhost:9090/info # topology (library / volume count)Metrics are prefixed thurvtl_* / thurvsa_*. Both daemons keep an
always-on, append-only, BLAKE3-chained audit log under
<data_dir>/audit/, with optional offsite shipping to a cloud
backend. The chain means any after-the-fact modification to the log
is detectable:
thurvtl system audit tail -f
thurvtl system audit verify # exit 0 valid, 1 break, 2 io errorTelemetry design — docs/TELEMETRY.md; audit
design — docs/AUDIT.md; opt-in email / webhook
alerting — docs/ALERTING.md.
cargo build [--release] # binaries in target/{debug,release}/
cargo test
cargo fmt && cargo clippy
# Run a daemon in the foreground from the build tree
RUST_LOG=info ./target/release/thurvtld --config thurvtl.yamlcargo test runs the workspace suite — 1,299 unit and integration
tests across the 38 crates. Measured with cargo llvm-cov, the storage
and protocol crates (storage engines, SCSI / NVMe command sets, dedup,
crypto, chunk pool) carry 75–95% line coverage; the daemon and CLI
integration surface is covered separately by the end-to-end conformance
suites under vtl/scripts/ and vsa/scripts/ (test-smoke.sh,
test-*-conformance.sh, and backup / filesystem workflow tests) — each
script's header documents its prerequisites and what it covers.
docs/TESTCOVERAGE.md has the per-crate
coverage breakdown, the methodology, and the suite catalogue.
The release-cut process is in docs/RELEASING.md;
the workspace crate map is in docs/WORKSPACE.md.
CLAUDE.md— architecture orientation and repo map.- Roadmap and open work — tracked as GitHub issues.
docs/TESTCOVERAGE.md— per-crate line coverage and the end-to-end suite catalogue.
Conformance — per-spec coverage tables plus the behavioral model:
docs/CONFORMANCE_SCSI.md— SPC-4 / SAM-5 / iSCSI / CHAP (shared baseline), the SSC-4 / SMC-3 tape surface with deliberate divergences from typical LTO hardware, and the SBC-3 block surface.docs/CONFORMANCE_NVME.md— NVMe Base / NVM Command Set / NVMe-oF / NVMe-TCP.
Wire-level & storage reference:
docs/SPEC.md— VTL wire surface, schemas, on-disk + cloud layout, DR / migration / archive.docs/STORAGE.md,docs/DEDUP.md,docs/CARTRIDGE.md,docs/BACKPRESSURE.md,docs/NVMETCP.md.
Operations: docs/CONFIGURATION.md,
docs/CLI.md,
docs/AUTH.md,
docs/AUDIT.md,
docs/TELEMETRY.md,
docs/ALERTING.md,
docs/RELEASING.md.
docs/CONFIGURATION.md catalogues every
configuration file and YAML key; the same per-key reference is what
<product> config defaults prints, checked in under
dist/.
Copyright (c) 2026 Mete Balci
Thur VTL and Thur VSA are licensed under the Apache License,
Version 2.0 (Apache-2.0). See the top-level LICENSE
file for the full text.
SPDX-License-Identifier: Apache-2.0