Overview

WolfDisk is a distributed file system that provides easy-to-use shared and replicated storage across Linux machines. Mount a shared directory on any number of servers and have your data automatically synchronised. Built on the same proven consensus mechanisms as WolfScale.

🎬 Watch the overview video: WolfDisk on YouTube

Key Features

  • FUSE-based — Mount as a regular Linux directory using FUSE3
  • Content-addressed deduplication — Automatic deduplication via SHA256 hashing
  • Chunk-based storage — Large files split into 4 MB chunks for efficient transfer and sync
  • Leader / Follower / Client modes — Flexible node roles for any deployment
  • Auto-discovery — UDP multicast for automatic peer discovery on LAN
  • Automatic leader election & failover — Deterministic election with 2-second failover
  • Delta sync — Incremental catchup β€” only missed changes are transferred
  • S3-compatible REST API — Optional S3 gateway for any S3 client
  • LZ4 compression — Compressed network replication
  • Symlink support — Full POSIX symlink support
  • IBM Power ready — Pure Rust dependencies, builds natively on ppc64le

Node Roles

Every WolfDisk node operates in one of four roles:

Role Storage Replication Use Case
Leader βœ… Yes Broadcasts to followers Primary write node
Follower βœ… Yes Receives from leader Read replicas, failover candidates
Client ❌ No None (mount-only) Access the drive remotely without local storage
Auto βœ… Yes Dynamic election Default β€” lowest node ID automatically becomes leader

πŸ’‘ Client Mode is perfect for workstations or containers that just need to access the shared filesystem without storing data locally.

Quick Install

The interactive installer handles dependencies, compilation, configuration, and systemd service setup:

bash
curl -sSL https://raw.githubusercontent.com/wolfsoftwaresystemsltd/WolfScale/main/wolfdisk/setup.sh | bash

The installer will prompt you for:

  • Node ID β€” Unique identifier (defaults to hostname)
  • Role β€” auto, leader, follower, or client
  • Bind IP address β€” IP to listen on (auto-detected)
  • Discovery method β€” Auto-discovery (UDP multicast), manual peers, or standalone
  • Mount path β€” Where to mount the filesystem (default: /mnt/wolfdisk)

⚠️ Compilation note: The installer compiles WolfDisk from source using Rust. This is CPU-intensive and may take several minutes. Please wait for it to complete.

Manual Installation

Prerequisites

  • Linux with FUSE3 support
  • Rust toolchain (rustup)

⚠️ Proxmox Users: If running in an LXC container, you must enable FUSE in the container options: Options β†’ Features β†’ FUSE

Install Dependencies

bash
# Ubuntu / Debian
sudo apt install libfuse3-dev fuse3

# Fedora / RHEL
sudo dnf install fuse3-devel fuse3

Build & Install

bash
git clone https://github.com/wolfsoftwaresystemsltd/WolfScale.git
cd WolfScale/wolfdisk
cargo build --release
sudo cp target/release/wolfdisk /usr/local/bin/
sudo cp target/release/wolfdiskctl /usr/local/bin/

Usage

1. Initialize Data Directory

bash
wolfdisk init -d /var/lib/wolfdisk

2. Mount the Filesystem

bash
# Foreground (for testing)
sudo wolfdisk mount -m /mnt/wolfdisk

# As a systemd service (recommended)
sudo systemctl start wolfdisk

3. Check Status

bash
wolfdiskctl status

4. Use It Like Any Directory

bash
# Write files
echo "Hello, WolfDisk!" > /mnt/wolfdisk/hello.txt
cp /var/log/syslog /mnt/wolfdisk/

# Read files β€” automatically available on all nodes
cat /mnt/wolfdisk/hello.txt
ls -la /mnt/wolfdisk/

Configuration

WolfDisk is configured via /etc/wolfdisk/config.toml. The installer creates this file for you, or you can edit it manually:

toml
[node]
id = "node1"                    # Unique node identifier
role = "auto"                   # auto, leader, follower, or client
bind = "0.0.0.0:9500"           # IP and port for cluster communication
data_dir = "/var/lib/wolfdisk"  # Where chunks and index are stored

[cluster]
# Auto-discovery (recommended for LAN)
discovery = "udp://239.255.0.1:9501"

# Or manual peers (for cross-subnet / WAN)
# peers = ["192.168.1.10:9500", "192.168.1.11:9500"]

[replication]
mode = "shared"       # "shared" or "replicated"
factor = 3            # Number of copies (replicated mode)
chunk_size = 4194304  # 4 MB chunks

[mount]
path = "/mnt/wolfdisk"
allow_other = true    # Allow other users to access the mount

# Optional: S3-compatible API
[s3]
enabled = true
bind = "0.0.0.0:9878"
# access_key = "your-access-key"   # optional auth
# secret_key = "your-secret-key"   # optional auth

Configuration Sections

Section Key Default Description
[node] id hostname Unique identifier β€” used in leader election (lowest ID wins)
role auto auto, leader, follower, or client
bind 0.0.0.0:9500 Listen address for cluster communication
data_dir /var/lib/wolfdisk Directory for chunks, index, and WAL
[cluster] discovery β€” UDP multicast address for auto-discovery
peers [] Manual list of peer addresses
[replication] mode shared shared (single leader) or replicated (N copies)
factor 3 Replication factor for replicated mode
chunk_size 4194304 Chunk size in bytes (4 MB)
[mount] path /mnt/wolfdisk FUSE mount point
allow_other true Allow other system users to access the mount
[s3] enabled false Enable S3-compatible REST API
bind 0.0.0.0:9878 S3 API listen address
access_key β€” Optional S3 access key
secret_key β€” Optional S3 secret key

Architecture

WolfDisk is composed of several layers that work together:

text
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      Linux Applications                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                    mount /mnt/wolfdisk                         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                       FUSE (fuser)                             β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                     WolfDisk Core                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  File Index  β”‚  β”‚  Chunk Store  β”‚  β”‚ Replication Engine   β”‚ β”‚
β”‚  β”‚  (metadata)  β”‚  β”‚   (SHA256)    β”‚  β”‚ (leader election)    β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚              S3-Compatible API (optional)                  β”‚ β”‚
β”‚  β”‚         ListBuckets / Get / Put / Delete Objects           β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚       Network Layer: Discovery + Peer Manager + Protocol       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

How It Works

  1. FUSE Layer β€” Applications read/write to /mnt/wolfdisk like a normal directory. The FUSE driver intercepts all filesystem calls.
  2. Chunk Store β€” Files are split into 4 MB chunks, each identified by its SHA256 hash. Identical data is automatically deduplicated.
  3. File Index β€” Maps file paths to their chunk references, permissions, size, and modification times.
  4. Replication Engine β€” Synchronises chunks and index updates across nodes. Handles leader election and failover.
  5. Network Layer β€” UDP multicast for peer discovery, TCP for data transfer. LZ4 compression for network efficiency.

Leader Election & Failover

WolfDisk uses deterministic leader election β€” no voting, no delays. The node with the lowest ID is always the leader.

How Failover Works

text
Initial State:
  node-a (leader) ←→ node-b (follower) ←→ node-c (follower)

node-a goes down:
  ❌ node-a         node-b detects timeout (2s)
                    node-b becomes leader (next lowest ID)

node-a returns:
  node-a syncs from node-b (gets missed changes)
  node-a becomes leader again (lowest ID)
  • Heartbeat timeout β€” Nodes monitor the leader with a 2-second timeout
  • Fast election β€” No voting or consensus delay; lowest node ID always wins
  • Seamless reads β€” Followers continue serving reads during failover
  • Explicit override β€” Set role = "leader" to force a specific node as leader

Sync & Replication

Write Replication

When the leader writes a file:

  1. Local write β€” Leader stores chunks and updates the file index locally
  2. Broadcast β€” Leader sends the index update and chunk data to all followers
  3. Apply β€” Followers update their local index and store the chunks

Delta Sync (Catchup)

When a node starts or recovers from downtime, it performs an incremental sync:

text
Follower (version 45) β†’ Leader: "SyncRequest(from_version=45)"
Leader (version 50)   β†’ Follower: "SyncResponse(entries=[5 changes])"
Follower applies 5 changes, now at version 50

Only missed changes are transferred β€” a node that was down briefly doesn't need to re-download everything.

Read Caching

Followers cache chunks locally for fast reads:

  • Cache hit β€” Chunk exists locally β†’ return immediately
  • Cache miss β€” Fetch chunk from leader β†’ cache locally β†’ return

Client Mode (Thin Client)

Client mode mounts the filesystem without storing any data locally. All reads and writes are forwarded to the leader over the network.

Aspect Leader / Follower Client
Local Storage βœ… Stores data on disk ❌ No local storage
Reads Served locally Forwarded to leader
Writes Local (leader) or forwarded Forwarded to leader
Use Case Data nodes, replicas Workstations, containers

Client mode is ideal for:

  • Workstations accessing shared files
  • Containers that need cluster storage access
  • Read-heavy applications where network latency is acceptable

S3-Compatible API

WolfDisk can optionally expose an S3-compatible REST API, allowing any S3 client (AWS CLI, rclone, MinIO Client, etc.) to read and write files. Both FUSE and S3 access the same underlying data β€” files written via FUSE are instantly visible through S3, and vice versa.

Enable S3

Add to /etc/wolfdisk/config.toml:

toml
[s3]
enabled = true
bind = "0.0.0.0:9878"
# Optional authentication:
# access_key = "your-access-key"
# secret_key = "your-secret-key"

How It Maps

WolfDisk S3 Equivalent
Top-level directory Bucket
File in directory Object
Nested directory Object key prefix

Supported Operations

Operation Method Path
ListBuckets GET /
CreateBucket PUT /bucket
DeleteBucket DELETE /bucket
HeadBucket HEAD /bucket
ListObjectsV2 GET /bucket?prefix=...
GetObject GET /bucket/key
PutObject PUT /bucket/key
DeleteObject DELETE /bucket/key
HeadObject HEAD /bucket/key

Examples

bash
# Using AWS CLI
aws --endpoint-url http://localhost:9878 s3 ls
aws --endpoint-url http://localhost:9878 s3 cp file.txt s3://mybucket/file.txt
aws --endpoint-url http://localhost:9878 s3 ls s3://mybucket/

# Using curl
curl http://localhost:9878/mybucket/myfile.txt
curl -X PUT --data-binary @file.txt http://localhost:9878/mybucket/file.txt

CLI Reference

wolfdisk (Service Daemon)

Command Description
wolfdisk init -d PATH Initialize a new WolfDisk data directory
wolfdisk mount -m PATH Mount the filesystem at the given path
wolfdisk unmount -m PATH Unmount the filesystem
wolfdisk status Show node configuration

Options:

  • --config PATH β€” Path to config file (default: /etc/wolfdisk/config.toml)

wolfdiskctl (Control Utility)

Command Description
wolfdiskctl status Show live status from the running service (role, state, version, file count, size, peers)
wolfdiskctl list servers List all discovered servers in the cluster with roles and status
wolfdiskctl stats Live cluster statistics dashboard (refreshes every second, Ctrl+C to exit)

Options:

  • -s, --status-file PATH β€” Path to status file (default: /var/lib/wolfdisk/cluster_status.json)

Systemd Service

The installer creates a systemd service for you automatically. Common commands:

bash
# Start WolfDisk
sudo systemctl start wolfdisk

# Check status
sudo systemctl status wolfdisk

# View logs
sudo journalctl -u wolfdisk -f

# Enable on boot
sudo systemctl enable wolfdisk

# Restart after config change
sudo systemctl restart wolfdisk

Multi-Node Setup

A typical deployment has multiple nodes with different roles. All nodes with role = "auto" will automatically elect a leader.

Server 1 (will become leader β€” lowest ID)

toml
[node]
id = "node-a"
role = "auto"
bind = "192.168.1.10:9500"
data_dir = "/var/lib/wolfdisk"

[cluster]
discovery = "udp://192.168.1.10:9501"

[mount]
path = "/mnt/shared"

Server 2–N (will become followers β€” higher IDs)

toml
[node]
id = "node-b"          # Higher ID β†’ follower
role = "auto"
bind = "192.168.1.11:9500"
data_dir = "/var/lib/wolfdisk"

[cluster]
discovery = "udp://192.168.1.11:9501"

[mount]
path = "/mnt/shared"

Workstation (client only β€” no storage)

toml
[node]
id = "desktop"
role = "client"
bind = "192.168.1.50:9500"

[cluster]
peers = ["192.168.1.10:9500", "192.168.1.11:9500"]

[mount]
path = "/mnt/shared"

Troubleshooting

Mount fails with "Transport endpoint not connected"

The FUSE mount is stale. Unmount and remount:

bash
sudo fusermount -u -z /mnt/wolfdisk
sudo systemctl restart wolfdisk

Permission denied on mount

Ensure user_allow_other is enabled:

bash
echo "user_allow_other" | sudo tee -a /etc/fuse.conf

Peers not discovering each other

  • Check that port 9500 (TCP) and 9501 (UDP) are open in your firewall
  • For cross-subnet setups, use peers = [...] instead of UDP discovery
  • Verify bind is set to an accessible IP, not 127.0.0.1

Status file not found

If wolfdiskctl status reports "Status file not found", the service is not running:

bash
sudo systemctl start wolfdisk
sudo journalctl -u wolfdisk -f    # Check for errors

Client Reset

If a client node (not leader/follower!) has a stuck mount or corrupted cache, use the reset script:

bash
sudo bash /opt/wolfscale-src/wolfdisk/reset_client.sh

⚠️ Warning: The reset script wipes /var/lib/wolfdisk. Only use it on client nodes. Running it on a leader or follower will cause data loss.

Network Ports

Port Protocol Purpose
9500 TCP Cluster communication (data, replication, sync)
9501 UDP Auto-discovery (multicast)
9878 TCP S3-compatible API (when enabled)