Skip to content

4nonX/DPlaneOS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

980 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DPlaneOS

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.

Version License NixOS CI

DPlaneOS Demo

Click the screenshot for an interactive tour of the UI.


Project status

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.


How is this possible as a solo project

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.


Acknowledgements

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.


Getting Started

Install to disk (permanent):

Try live boot (no installation needed):

  • Download the latest live ISO (same releases, look for -live in filename)
  • Flash to USB and boot
  • Full D-PlaneOS in RAM, ephemeral state, auto-import existing ZFS pools
  • See Live Boot Quick Start

What it does

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.

Install

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
  1. Boot the target machine from USB.
  2. The installer launches automatically. Enter disk, hostname, SSH key.
  3. DPlaneOS installs and starts within minutes.
  4. 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.

Minimum hardware

  • 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

Architecture

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.


Key paths

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

Quick command reference

# 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

Documentation

Installation and operation

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

Reference

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

Hardware

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

NixOS

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

Development

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

Legal

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)

License

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.

About

NixOS native, ZFS-first NAS operating system for advanced homelab operators. Focused on immutability, safe container lifecycle management, and reproducible infrastructure.

Topics

Resources

License

Contributing

Security policy

Stars

10 stars

Watchers

0 watching

Forks

Contributors