Skip to content

Latest commit

 

History

2,211 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DittoFS

Go Version Nix Flake Go Report Card License: MIT Status

Unit Tests Integration Tests E2E Tests Lint Conformance NFS Conformance

A modular virtual filesystem written entirely in Go

NFSv3/v4.0/v4.1/v4.2 and SMB2/3 servers in userspace — no FUSE, no kernel modules — with pluggable metadata and block stores you can mix and match per share.

WebsiteQuick StartDocumentationFeaturesContributing


⚠️ Experimental software, pre-1.0. Not production ready. No security audit has been performed. APIs and on-disk formats may change without notice. Do not use for data you cannot afford to lose. See Security and FAQ.

What is DittoFS?

Traditional file servers are welded to one storage layer and one access protocol. DittoFS separates the two. A single server process can:

  • Speak NFSv3, NFSv4.0, NFSv4.1, NFSv4.2, and SMB2/3 at the same time, over the same data.
  • Store metadata in memory, BadgerDB, or PostgreSQL — chosen per share.
  • Store file content in one block store (S3 or memory) per share, fronted by an on-disk journal that absorbs writes, with an async syncer between them.
  • Run entirely in userspace — no FUSE, no kernel modules, no special privileges.

Everything is built from named, reusable stores wired together into shares. Two binaries drive it:

Binary Role
dfs The server daemon — runs the protocol adapters and a control-plane REST API.
dfsctl The REST client — manages users, groups, shares, stores, and adapters on a running server.

Features

Area Status
NFSv3 All 28 core procedures; embedded portmapper + mount protocol; NLM/NSM byte-range locking over TCP+UDP (opt-in)
NFSv4.0 Compound ops, ACLs, delegations, built-in byte-range locking
NFSv4.1 Sessions, sequence slots, backchannel
NFSv4.2 Extended attributes (RFC 8276); sparse files — ALLOCATE/DEALLOCATE/SEEK/READ_PLUS; CLONE/reflink (RFC 7862)
SMB 2.0.2 / 3.0 / 3.0.2 / 3.1.1 Multi-dialect negotiation, preauth integrity, compound requests
SMB3 encryption AES-128/256-GCM and AES-128/256-CCM
SMB3 signing AES-128-CMAC / AES-128-GMAC (HMAC-SHA256 for 2.x)
SMB leases & oplocks Leases V2 with directory leasing; oplocks; byte-range locks
SMB durable handles V1 and V2 for session resilience
SMB security descriptors Windows ACL mapping via a shared cross-protocol ACL model
Authentication AUTH_UNIX + Kerberos (RPCSEC_GSS) for NFS; NTLM + Kerberos (SPNEGO) for SMB
Active Directory Kerberos service keytab for AD-issued tickets; optional machine account (offline or online domain join) for NTLM pass-through; LDAP idmap (idmap_ad / idmap_rid) maps AD users and nested groups to the same Unix UID/GID over SMB and NFS
Cross-protocol coordination Bidirectional lease/delegation breaks between SMB and NFS
Metadata stores Memory, BadgerDB, SQLite, PostgreSQL — pluggable per share
Block stores S3, memory. One per share, fronted by an on-disk journal. Per-share isolation, async sync
Client-side encryption Per-remote envelope encryption (AES-256-GCM / ChaCha20-Poly1305 / XChaCha20-Poly1305)
Share snapshots Point-in-time reference holds (no data copy) with restore
Control plane Unified users/groups, share permissions, REST API with JWT auth
Observability Prometheus metrics endpoint, structured JSON logging
Deployment Single static binary; Docker images; Kubernetes operator

DittoFS passes the pjdfstest POSIX suite at 99.99% (8,788/8,789) across all three metadata backends; the single expected failure is the NFSv3 32-bit timestamp limit (year 2106). See the FAQ for known limitations.

On the SMB side, DittoFS passes the Samba smbtorture and Microsoft Windows Protocol Test Suite (WPTS) conformance batteries on the implementable surface — every test that a single-node userspace VFS can satisfy. The remaining known-failures are genuinely out-of-scope features (RSVD shared-VHD, Service Witness clustering, Storage QoS, DFS namespaces, kernel oplocks, NTFS-internal pseudo-files) plus a handful of upstream-Samba known-fails; none are fixable protocol gaps. See docs/guide/smb.md and docs/guide/windows.md.

DittoFS PRO

The community edition is fully open source. DittoFS PRO adds a web management UI and commercial support on top of the same engine, for teams running DittoFS in production.

DittoFS PRO management console

Manage users, shares, stores, and protocol adapters from one console. Learn more at dittofs.io/pro.

Quick Start

Install

# Nix (runs without installing)
nix run github:marmos91/dittofs -- init
nix run github:marmos91/dittofs -- start

# Homebrew
brew tap marmos91/tap
brew install marmos91/tap/dfs marmos91/tap/dfsctl

# Quick install script (macOS / Linux)
curl -fsSL https://github.com/marmos91/dittofs/releases/latest/download/install.sh | sh

Docker, the Kubernetes operator, APT/YUM/Arch packages, and Scoop (Windows) are covered in docs/guide/install.md.

Build from source

git clone https://github.com/marmos91/dittofs.git
cd dittofs
go build -o dfs    cmd/dfs/main.go
go build -o dfsctl cmd/dfsctl/main.go
./dfs init     # writes ~/.config/dittofs/config.yaml
./dfs start

First run & admin password

On first start, DittoFS creates an admin user. Pre-set the password via the DITTOFS_ADMIN_INITIAL_PASSWORD environment variable — this is the recommended path for every deployment, and the only reliable one for Docker/Kubernetes/CI and systemd:

# Choose your own password (also skips the forced password change on first login)
DITTOFS_ADMIN_INITIAL_PASSWORD=my-secure-password ./dfs start

If you don't pre-set it, a random password is generated — but it is shown only when you run ./dfs start --foreground in an interactive terminal (printed once). In background mode (the default ./dfs start), and under Docker/systemd where stdout is a pipe rather than a terminal, the generated password is not written to the log and cannot be recovered. Because the admin user is created on that first start, setting DITTOFS_ADMIN_INITIAL_PASSWORD and simply restarting will not change it — that variable is only read while bootstrapping a new admin. To recover, delete the admin row from the users table of the control-plane database and start again with the password pre-set; the next start re-runs the bootstrap. Do not delete the database itself — it also holds your shares, stores, mounts and other users. So: set it before the very first start.

Serve an NFS share in under a minute

# 1. Start the server (see above), then log in
./dfsctl login --server http://localhost:8080 --username admin

# 1a. REQUIRED on first login: change the admin password.
# The bootstrap admin starts with a forced-password-change flag — until you
# clear it here, every other command (including `user create` below) is
# rejected with HTTP 403:
#   account "admin" must set a new password before performing other operations;
#   run 'dfsctl user change-password' (as "admin") to set one
# This forced change is skipped automatically when you set your own
# DITTOFS_ADMIN_INITIAL_PASSWORD at first start, and can be disabled entirely
# via controlplane.require_initial_password_change: false (see docs/guide/configuration.md).
./dfsctl user change-password

# 2. Create a user mapped to your host UID (needed for NFS write access)
./dfsctl user create --username $(whoami) --host-uid

# 3. Create the stores (interactive prompts collect paths / S3 credentials)
./dfsctl store metadata add --name default --type badger
./dfsctl store block add --name s3-remote --type s3

# 4. Create a share and grant access
./dfsctl share create --name /export --metadata default --block-store s3-remote
./dfsctl share permission grant /export --user $(whoami) --level read-write

# 5. Enable the NFS adapter
./dfsctl adapter enable nfs

# 6. Mount it
# Linux:
sudo mount -t nfs -o tcp,port=12049,mountport=12049 localhost:/export /mnt/nfs
# macOS:
sudo mount -t nfs -o tcp,port=12049,mountport=12049,resvport,nolock localhost:/export /tmp/nfs

echo "Hello DittoFS!" > /mnt/nfs/hello.txt

This uses persistent storage (BadgerDB metadata, S3 durable backend). Writes land in the share's on-disk journal first and sync to S3 in the background. For dependency-free local testing, use --type memory for both the metadata and block stores instead.

Mount an SMB share

SMB always requires user authentication:

./dfsctl user create --username alice            # password prompted
./dfsctl share permission grant /export --user alice --level read-write

# Linux (use a credentials file — never put passwords on the command line)
sudo mount -t cifs //localhost/export /mnt/smb \
  -o port=12445,credentials=$HOME/.smbcredentials,vers=3.1.1

# macOS (prompts for password)
mount -t smbfs //alice@localhost:12445/export /tmp/smb

See docs/guide/smb.md for dialect, encryption, and client details.

Default ports

Port Service
12049 NFS
12445 SMB
8080 Control-plane REST API (health checks, management)
9090 Prometheus metrics

Configuration model

DittoFS configuration has two layers:

  1. Server config file (~/.config/dittofs/config.yaml) — process-level infrastructure: logging, metrics, control-plane API, and the control-plane database. Environment variables with the DITTOFS_ prefix override any field (e.g. DITTOFS_LOGGING_LEVEL=DEBUG).
  2. Runtime resources (dfsctl / REST API) — stores, shares, adapters, users, groups, and permissions. These live in the control-plane database (SQLite by default, PostgreSQL for HA), not in the config file.
# ~/.config/dittofs/config.yaml
database:
  type: sqlite            # or "postgres" for HA
  sqlite:
    path: ~/.config/dittofs/controlplane.db   # default when omitted: $XDG_CONFIG_HOME/dittofs/controlplane.db

controlplane:
  port: 8080
  jwt:
    secret: "your-secret-key-at-least-32-characters"

Block storage is configured per share through the store CLI — each share points at one block store and owns an isolated journal directory beneath blockstore.journal.path. See docs/guide/configuration.md for the full reference.

Documentation

Full docs live in docs/, split by audience.

For users & operators — docs/guide/

Start here

Connect clients

Features & operations

For contributors — docs/internals/

Product

  • DittoFS Pro — the managed dashboard built on open-source DittoFS

Testing

go test ./...                    # unit + integration
go test -race ./...              # with the race detector

# E2E (needs sudo + a kernel NFS client)
cd test/e2e && sudo ./run-e2e.sh

See test/e2e/ (and test/e2e/BENCHMARKS.md) and docs/internals/contributing.md.

Security

DittoFS is experimental and has not been professionally audited.

  • Authentication: AUTH_UNIX and Kerberos (RPCSEC_GSS) for NFS; NTLM and Kerberos (SPNEGO) for SMB. AD domain users can authenticate directly against a directory — see docs/guide/identity.md.
  • Transport encryption: SMB3 encrypts its transport (AES-GCM/CCM). NFS supports NFS-over-TLS (RFC 9289) and Kerberos privacy (krb5p); without either, run NFS over a VPN or a trusted network.
  • At-rest: optional client-side per-remote envelope encryption protects block content in the remote store. See docs/guide/encryption.md.

See docs/guide/security.md for the full picture and recommendations.

Contributing

Contributions are welcome — see docs/internals/contributing.md for development setup, code structure, and testing guidelines.

References

New to these protocols? Start with the Glossary for plain-language definitions, then dive into the authoritative specs below.

DittoFS Pro

DittoFS Pro is the premium edition: a modern web dashboard that brings the same capabilities as the dfsctl CLI — managing stores, shares, adapters, and access control — to a point-and-click web UI. It builds on this open-source server and ships as a single binary with the UI embedded. Learn more at dittofs.io.

DittoFS Pro dashboard

License

MIT — see LICENSE.

About

A modular virtual filesystem written entirely in Go

Topics

Resources

Contributing

Stars

49 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages