πΎ WolfDisk
Distributed filesystem for sharing and replicating files across your network
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:
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
# Ubuntu / Debian
sudo apt install libfuse3-dev fuse3
# Fedora / RHEL
sudo dnf install fuse3-devel fuse3
Build & Install
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
wolfdisk init -d /var/lib/wolfdisk
2. Mount the Filesystem
# Foreground (for testing)
sudo wolfdisk mount -m /mnt/wolfdisk
# As a systemd service (recommended)
sudo systemctl start wolfdisk
3. Check Status
wolfdiskctl status
4. Use It Like Any Directory
# 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:
[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:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 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
- FUSE Layer β Applications read/write to
/mnt/wolfdisklike a normal directory. The FUSE driver intercepts all filesystem calls. - Chunk Store β Files are split into 4 MB chunks, each identified by its SHA256 hash. Identical data is automatically deduplicated.
- File Index β Maps file paths to their chunk references, permissions, size, and modification times.
- Replication Engine β Synchronises chunks and index updates across nodes. Handles leader election and failover.
- 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
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:
- Local write β Leader stores chunks and updates the file index locally
- Broadcast β Leader sends the index update and chunk data to all followers
- 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:
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:
[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
# 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:
# 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)
[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)
[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)
[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:
sudo fusermount -u -z /mnt/wolfdisk
sudo systemctl restart wolfdisk
Permission denied on mount
Ensure user_allow_other is enabled:
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
bindis set to an accessible IP, not127.0.0.1
Status file not found
If wolfdiskctl status reports "Status file not found", the service is not running:
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:
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) |