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.
Website • Quick Start • Documentation • Features • Contributing
⚠️ 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.
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. |
| 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.
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.
Manage users, shares, stores, and protocol adapters from one console. Learn more at dittofs.io/pro.
# 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 | shDocker, the Kubernetes operator, APT/YUM/Arch packages, and Scoop (Windows) are covered in docs/guide/install.md.
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 startOn 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 startIf 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.
# 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.txtThis 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 memoryfor both the metadata and block stores instead.
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/smbSee docs/guide/smb.md for dialect, encryption, and client details.
| Port | Service |
|---|---|
12049 |
NFS |
12445 |
SMB |
8080 |
Control-plane REST API (health checks, management) |
9090 |
Prometheus metrics |
DittoFS configuration has two layers:
- Server config file (
~/.config/dittofs/config.yaml) — process-level infrastructure: logging, metrics, control-plane API, and the control-plane database. Environment variables with theDITTOFS_prefix override any field (e.g.DITTOFS_LOGGING_LEVEL=DEBUG). - 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.
Full docs live in docs/, split by audience.
For users & operators — docs/guide/
Start here
- Getting Started — install, start the server, mount your first share
- Installation — packages, Docker, Compose, Kubernetes operator
- Configuration — every config key and environment variable, with defaults
- CLI Reference — every
dfsanddfsctlcommand (generated) - Choosing Stores — picking metadata and block stores
- Sizing & Hardware — how to size the machine that runs
dfs
Connect clients
- NFS — mounting on Linux/macOS, options, Kerberos, NFS-over-TLS
- SMB — mounting, dialects, encryption, signing
- Windows clients — connecting from Windows
- Identity: AD / LDAP / Kerberos — join a directory service
- Access Control — the cross-protocol ACL model
- SMB ACL Fidelity — what the SMB Security Descriptor path round-trips (Works/Partial/Unsupported)
Features & operations
- Snapshots · Quotas · Encryption
- Security — hardening checklist and secure configuration
- Block Store Migration — migrating legacy block layouts to CAS
- Troubleshooting · FAQ · Glossary
For contributors — docs/internals/
- Architecture — design, components, directory map
- NFS protocol · SMB protocol — wire format, dispatch, internals
- ACL design · Security model · Encryption design
- Implementing Stores — metadata/block store contracts
- Testing — Windows VM setup, WPTS & smbtorture conformance
- Debugging — protocol interop and pcap-diff playbook
- Contributing · Releasing
- DittoFS Pro — the managed dashboard built on open-source DittoFS
go test ./... # unit + integration
go test -race ./... # with the race detector
# E2E (needs sudo + a kernel NFS client)
cd test/e2e && sudo ./run-e2e.shSee test/e2e/ (and test/e2e/BENCHMARKS.md) and docs/internals/contributing.md.
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.
Contributions are welcome — see docs/internals/contributing.md for development setup, code structure, and testing guidelines.
New to these protocols? Start with the Glossary for plain-language definitions, then dive into the authoritative specs below.
- RFC 1813 — NFS Version 3
- RFC 7530 — NFS Version 4.0
- RFC 8881 — NFS Version 4.1
- RFC 5531 — ONC RPC Protocol
- RFC 4506 — XDR Standard
- MS-SMB2 — SMB2/3 protocol
- MS-DTYP — SID, ACL, ACE, and security descriptor formats
- MS-NLMP — NTLM authentication
- RFC 4120 — Kerberos V5 · RFC 4178 — SPNEGO · RFC 2743 — GSS-API
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.
MIT — see LICENSE.

