A ZFS-first storage operating system for homelab and small-office NAS deployments. Single Go daemon, PostgreSQL state, React UI, NixOS appliance. Declarative from the OS down to the dataset.
Click the screenshot for an interactive tour of the UI.
Read this before you deploy anything.
DPlaneOS is built and maintained by one person (hi, Dan). It runs in my own homelab on roughly 33 TB across 60+ services and has done so reliably for months, which is the entire production deployment base I can point to. If you need vendor support, a roadmap committee, or a phone number to call at 3am, this is not the project for you. Yet.
Feature maturity, honestly:
| Area | Status | Notes |
|---|---|---|
| ZFS pool / dataset / snapshot management | Stable | The core. Used daily. |
| SMB, NFS, iSCSI sharing | Stable | Samba + kernel NFS + LIO. |
| Container management (Docker, Compose) | Stable | Including ZFS-clone sandboxes. |
| Hot-swap detection and auto-import | Stable | udev + ZED, exercised regularly. |
| LDAP / Active Directory integration | Beta | Winbind NSS integration shipped in v14.1.0: AD users resolve in ls -l, ACLs, and SMB. |
| OIDC / SSO (Authorization Code + PKCE) | Beta | Keycloak, Authentik, Dex, Entra ID, and any OIDC-compliant provider. |
| Enterprise Licensing & Compliance Engine | Stable | Ed25519 offline license verification. Optional compliance reporting sidecar. Automatic activation and expiration handling. |
| A/B OTA updates with auto-revert | Beta | Mechanism is sound, sample size is small. |
| Live boot (ephemeral, no install needed) | Stable | Trial the software, manage pools, run containers from USB. Full daemon/UI in RAM. Persistence optional via USB. |
| GitOps reconciliation | Beta | Structural sync (pools, datasets, shares, stacks) and capture-from-live both work. Safety rails (block destroy on used data, block pool destroy unconditionally) are well-tested. Edge cases at the property-coverage frontier still surfacing. |
| Out-of-band hardware management (BMC) | Beta | Redfish (iLO 5+, iDRAC 9+), iLO 4 legacy REST, generic IPMI. TOFU TLS certificate pinning. Sensors, event log, power management. |
| PostgreSQL HA (Patroni + etcd) | Experimental | Tested in lab, never under real load. |
| Replicated-topology HA with witness | Experimental | Same. Read the Showstopper Mitigation Guide first. Network quorum witness (VPS ping-based) added in v14.1.0. |
| Shared-SAS HA with SCSI-3 PR fencing | Experimental | Tested on one hardware configuration. Yours will differ. |
| NVMe-oF over TCP | Experimental | Functional, not yet stress-tested. |
If you're considering this for anything beyond a homelab, also read the Threat Model (13 scenarios, known gaps documented) and the Non-ECC RAM Warning.
Bug reports are welcome. So are contributors; the CLA is upfront about copyright assignment, which some people will not be comfortable with. Fair.
Reasonable question. The short answer: most of DPlaneOS isn't DPlaneOS.
NixOS does the heavy lifting. The OS, the bootloader, service supervision, the package set, reproducible builds, generation-based rollbacks, firewall, user management, kernel module loading, the whole declarative configuration model. None of that is my code. NixOS already solved it, better than I could in ten lifetimes. DPlaneOS is a NixOS module and a daemon that drives it.
OpenZFS does the storage. Pools, datasets, snapshots, send/receive, encryption, ARC tuning, scrub, resilver, integrity checking, all of it. The daemon shells out to zfs and zpool with allowlisted arguments and parses the output. That's it. The hard storage problems were solved by Sun, then Illumos, then OpenZFS, over twenty years.
The system stack is well-trodden upstream software. PostgreSQL for state, nginx for the edge, Patroni and etcd for HA consensus, Keepalived for VIPs, Samba for SMB, the kernel for NFS and LIO/iSCSI, Docker for containers, NUT for UPS, rclone for cloud sync, ZED for ZFS event delivery. Each of these has more engineering hours behind it than I will produce in my career.
The Go dependency tree is deliberately small. Nine direct dependencies: gorilla/mux, gorilla/websocket, pgx, go-ldap, lego (ACME), creack/pty, google/uuid, golang.org/x/crypto, go-jose/v4 (OIDC JWS verification). All vendored. The daemon is not a wrapper around a large framework; it's standard library plus narrow, well-understood plumbing.
So what's actually new code?
The seams. ~49k lines of Go that tie the above together coherently: ~400 HTTP routes mapping UI intent to allowlisted exec calls, state persisted in PostgreSQL with goose migrations, a reconciler that compares declared state against observed state and handles drift, an HMAC-chained audit log, ZED events surfaced over WebSocket, the A/B OTA flow with health-checked auto-revert, the HA state machine including SCSI-3 PR fencing and Patroni integration. None of this is exotic computer science. All of it is integration work that nobody else had bothered to do under one roof.
The interface. ~30k lines of React 19 / TypeScript: 48 pages, around 67 modal/dialog components, one embedded PTY terminal. Aimed at someone who would rather not memorise zpool flags or hand-edit a Samba config.
The GitOps layer. A declarative state.yaml schema and a bi-directional reconciler that lets you treat a Git repo as the source of truth for the shape of your storage: pools, dataset hierarchy and properties (quota, compression, atime, recordsize, encryption, mountpoint), shares, NFS exports, container stacks, users, replication relationships. You can apply changes from Git to the live system, or capture the live state back into Git. What it does not manage is the data plane itself: dataset contents, snapshots, and zfs send streams stay on ZFS's terms and are backed up out of band. The reconciler is also conservative in the places that matter: pool destruction is always BLOCKED, dataset destruction is BLOCKED whenever zfs get used is non-zero, and there's an ignore_extraneous flag for partial declarations. A git push cannot wipe data; only metadata and configuration. This is the part I'm proudest of and also the part most likely to have rough edges at the property-coverage frontier.
That's the honest accounting. DPlaneOS exists because NixOS, OpenZFS, PostgreSQL, and a dozen other projects exist. The work I did is the integration layer and the UX. Both are real work, neither is "building a storage OS from scratch," and pretending otherwise would be insulting to the upstream projects this whole thing rests on.
DPlaneOS stands on the shoulders of decades of work by people I have never met. A non-exhaustive list of the projects this would not exist without:
The foundation. NixOS and Nixpkgs for the declarative OS model that makes the whole appliance approach feasible. OpenZFS for the filesystem the project is named after and built around. PostgreSQL for state that doesn't lose itself.
The services. nginx, HAProxy, Samba, Patroni, etcd, Keepalived, Docker, the Linux kernel's NFS and LIO/iSCSI subsystems, rclone, smartmontools. Each one a project I have used for years and never had cause to regret picking.
The libraries. gorilla/mux and gorilla/websocket, jackc/pgx, go-ldap, go-acme/lego, creack/pty, go-jose/v4. Plus the Go team's golang.org/x/crypto and friends.
The frontend. React, TanStack Router and Query, Zustand, xterm.js, Vite. The Outfit and JetBrains Mono typefaces, plus Material Symbols.
Full license inventory and attribution in NOTICE.md.
Install to disk (permanent):
- Download the latest installer ISO
- Follow the Installation Guide
- Full disk installation with OTA updates
Try live boot (no installation needed):
- Download the latest live ISO (same releases, look for
-livein filename) - Flash to USB and boot
- Full D-PlaneOS in RAM, ephemeral state, auto-import existing ZFS pools
- See Live Boot Quick Start
| Area | Capabilities |
|---|---|
| Storage | ZFS pools, datasets, snapshots, zfs send replication, native encryption, quotas, S.M.A.R.T., POSIX ACLs, file explorer with chunked uploads |
| Hot-swap | udev detects disk add/remove; daemon auto-imports FAULTED/UNAVAIL pools and suggests vdev replacements in the UI |
| Sharing | SMB (with Time Machine via vfs_fruit), NFS, iSCSI, NVMe-oF, configured from the UI |
| Containers | Docker, Compose stacks, ephemeral ZFS-clone sandboxes, atomic updates with rollback, in-browser terminal. Intel VA-API hardware transcoding supported (Jellyfin, Plex). |
| Network | Interface config, bonding, VLANs, routing, DNS |
| Identity | Local users, LDAP / AD with Winbind NSS integration (AD users visible in ls -l, ACLs, SMB), OIDC SSO (Authorization Code + PKCE), TOTP 2FA, SCRAM-SHA-512, API tokens |
| Security | RBAC (4 roles, 34 permissions), HMAC audit chain, CSRF protection, firewall, TLS, allowlist-validated exec calls, govulncheck in CI |
| Hardware | BMC management via Redfish (iLO 5+, iDRAC 9+), iLO 4, or IPMI. TOFU TLS certificate pinning. Temperature, fan, power sensors. Power management and event log. |
| Monitoring | Prometheus/OpenMetrics at /metrics: ZFS pool health (4-level), dataset usage/quota, scrub progress, HA peer health, replication status, BMC sensors, build info |
| HA | Optional, off by default. Enable/disable from the UI with a single toggle. Two paths: shared-SAS with SCSI-3 PR fencing (no witness needed); replicated ZFS with IPMI/PDU/SBD/network-quorum witness. Graceful primary handoff (Patroni switchover) before disable. |
| System | Dashboard, logs, UPS (NUT), hardware auto-tuning, cloud sync (rclone), HA node monitoring |
| GitOps | Git-sync repositories, bi-directional reconciliation, drift detection. Manages structure (pools, dataset properties, shares, stacks, users), not data. Destructive operations on used datasets and pools are blocked by default. |
Boot the installer ISO. It handles everything.
# Write the ISO to USB (Linux/macOS)
dd if=dplaneos-v*.iso of=/dev/sdX bs=4M status=progress conv=fsync- Boot the target machine from USB.
- The installer launches automatically. Enter disk, hostname, SSH key.
- DPlaneOS installs and starts within minutes.
- Open
http://<your-server-ip>/. Change the admin password on first login.
Download: Latest release. Grab dplaneos-v*-installer-amd64.iso (x86_64) or ...-arm64.iso (aarch64, including Raspberry Pi 5). The combined installer handles NAS installation and, for replicated-topology HA clusters, witness-node installation via a boot menu. Shared-SAS clusters need only the two data-node ISOs.
Offline / air-gapped: the ISO contains the complete NixOS closure. No internet access needed during installation. Note: Intel VA-API hardware transcoding packages (intel-media-driver, intel-compute-runtime) are not included in the ISO to keep it under 2 GB. Run nixos-rebuild once the system is online to install them. All core NAS features work immediately from an offline install.
Cosign / provenance: every ISO is signed with cosign and accompanied by an SPDX SBOM. Verify with cosign verify-blob --bundle dplaneos-v*.iso.bundle dplaneos-v*.iso.
Rebuilding from source: nix build .#iso. See nixos/README.md.
- 64-bit CPU, x86_64 or aarch64 (Raspberry Pi 5 supported)
- 8 GB RAM minimum, 16 GB recommended, more for large pools
- ECC RAM strongly recommended for ZFS; non-ECC is supported but read the warning first
- One disk for the OS, plus the disks you intend to pool
- Full compatibility list: Hardware Compatibility
The runtime is a single statically-linked Go daemon (dplaned) sitting behind nginx, with PostgreSQL for state. The daemon talks to ZFS, Docker, and the kernel via exec.Command with a strict allowlist (no shell, no string interpolation). The frontend is a pre-built React 19 bundle served as static files.
Browser
└── nginx :80/:443 static files from /opt/dplaneos/app/
└── proxy /api/ /ws/
└── dplaned (Unix socket) (Go)
├── PostgreSQL /var/lib/dplaneos/pgsql/ (embedded or Patroni-managed)
├── ZFS kernel module via allowlisted exec
├── Docker socket
└── LDAP/AD optional
| Component | Detail |
|---|---|
| Frontend | React 19 + TypeScript + Vite, pre-built, no Node.js at runtime |
| Backend | Go daemon, allowlist-validated exec, no shell invocation anywhere in the codebase |
| Database | PostgreSQL 15+ (Patroni for HA topologies) |
| Auth | SCRAM-SHA-512 (RFC 5802, 100k PBKDF2 iterations), bcrypt (web login over HTTPS), LDAP bind (directory accounts), OIDC Authorization Code + PKCE (SSO accounts), TOTP 2FA, AAL1/AAL2 session assurance levels, CSRF double-submit |
| ZFS events | ZED hook delivers pool fault, scrub, and resilver events in real time |
| BMC | Redfish (iLO 5+, iDRAC 9+), iLO 4 legacy REST, generic IPMI. TOFU TLS fingerprint pinning - no InsecureSkipVerify. |
| Observability | Prometheus/OpenMetrics at /metrics (no auth). ZFS, HA, replication, BMC sensor metrics. govulncheck on every CI run. cosign-signed releases with SPDX SBOMs. |
Deeper reading: Architecture, Design Philosophy, NixOS Rationale.
| Item | Path |
|---|---|
| Daemon binary | /opt/dplaneos/daemon/dplaned |
| Web UI (static) | /opt/dplaneos/app/ |
| Version file | /opt/dplaneos/VERSION |
| Database state | /var/lib/dplaneos/pgsql/ |
| DB configuration | /etc/dplaneos/patroni.yaml |
| Custom container icons | /var/lib/dplaneos/custom_icons/ |
| Logs | /var/log/dplaneos/ |
| ZED hook | /etc/zfs/zed.d/dplaneos-notify.sh |
# Service control
sudo systemctl status dplaned
sudo systemctl restart dplaned
sudo journalctl -u dplaned -f
# Health check
curl --unix-socket /run/dplaneos/dplaned.sock http://localhost/health
# Interactive recovery (locked out, DB issues, ZFS problems)
sudo dplaneos-recovery
# Database access
sudo -u postgres psql dplaneos -c "\dt"
# ZFS
zpool status
zpool import
# OTA upgrade
sudo dplaneos-ota-update| Document | What it covers |
|---|---|
| Installation Guide | Requirements, ISO install flow, post-install checklist, OTA upgrades |
| NixOS Install Guide | For NixOS beginners: empty hardware to running NAS |
| Administrator Guide | Users, roles, permissions, storage, containers, LDAP/AD, security |
| Git-Driven NAS | Operating DPlaneOS entirely via state.yaml: bootstrap, auto-apply, rollback, PR workflow, HA |
| Backup and Replication | Snapshots, ZFS send/receive, cloud sync, cold tier, rsync, DB backup, recovery |
| High Availability | HA is optional and off by default. Shared-SAS with SCSI-3 PR fencing, replicated ZFS with witness (etcd, network quorum, VPS ping), Patroni, Keepalived, STONITH, rolling upgrades |
| Integration Guide | Prometheus scrape config, Active Directory/Winbind, SMB HA behaviour, NVMe-oF client setup, iSCSI ALUA, GitOps/CI, HA timing, Docker hardware transcoding, GPU passthrough |
| OTA Updates | A/B slots, health check, auto-revert, manual rollback, HA rolling upgrades |
| Optional Protocols | iSCSI, NVMe-oF, FTP/FTPS, MinIO S3-compatible object store |
| Alerts and Authentication | SMTP, webhook, Telegram alerting, TOTP 2FA setup and backup codes |
| Troubleshooting | Build failures, ZFS issues, DB init race, Docker behind proxy, ZED setup |
| Recovery Guide | Service management, DB restore, admin lockout, ZFS recovery, hot-swap, rollback |
| Document | What it covers |
|---|---|
| Features | Complete feature list by category |
| Pitch | Git as control plane: the enterprise and fleet case |
| Design Philosophy | Four core principles, design decisions, tradeoffs |
| Architecture | Three-layer model, persistence, single-node and HA architecture |
| GitOps Reference | state.yaml format, reconciliation engine, drift detection, Capture workflow |
| Changelog | Full version history |
| Port Reference | Every port the system listens on, its service, interface binding, and safe ranges for Docker containers |
| Error Reference | Every HTTP error code the API returns, with cause and fix |
| NixOS Rationale | Why DPlaneOS is NixOS-exclusive |
| Porting Guide | Forking for other Linux distributions: what it takes, what you lose |
| Showstopper Mitigation Guide | Honest assessment of HA limits, binary trust, resolved vs open issues |
| Threat Model | Security architecture, 13 threat scenarios, mitigations, residual risks, known gaps |
| Dependencies | Bundled Go and frontend deps, system requirements, build instructions |
| Document | What it covers |
|---|---|
| Hardware Compatibility | CPUs, RAM, disk types, network, RAID controllers, auto-tuning |
| Non-ECC RAM Warning | Why ZFS plus non-ECC is risky, probability analysis, mitigations |
| Document | What it covers |
|---|---|
| NixOS Overview | ISO, Flake, and standalone install paths |
| NixOS Install Guide | Step-by-step for beginners |
| NixOS Technical Reference | Declarative config, rollback, licensing, advanced options |
| Document | What it covers |
|---|---|
| Contributing | Dev setup, project structure, coding conventions, security requirements for PRs |
| Codebase Diagram | Mermaid diagrams: system overview, daemon internals, request lifecycle, disk events, auth flow |
| Design System | Frontend design tokens, spacing grid, component patterns, anti-pattern list |
| Document | What it covers |
|---|---|
| License | GNU Affero General Public License v3.0 |
| Notice | Third-party components, attributions, and licenses |
| Security Policy | Vulnerability reporting, safe harbour, supported versions |
| Individual CLA | Contributor license agreement for individuals |
| Entity CLA | Contributor license agreement for organisations |
| PostgreSQL Migration Guide | Upgrading from SQLite to PostgreSQL (v7.0.0) |
DPlaneOS is licensed under the GNU Affero General Public License v3.0.
If you run a modified version of DPlaneOS and let others interact with it over a network, AGPL § 13 requires that you offer them the Corresponding Source. The unmodified source is at github.com/4nonX/DPlaneOS; if you have modified it, you must make your modifications available to your users on equivalent terms.
Third-party components and their licenses are listed in NOTICE.md.
