Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions disk-configs/zfs-nas.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# ZFS NAS disk configuration
# Boot disk (ext4) + ZFS data pool for document/media storage
#
# Deployment notes:
# Disk assignments use lib.mkDefault so nixos-anywhere (or a host-specific
# overlay) can override the actual device paths at install time.
#
# For mirror or RAIDZ layouts, add additional disks below that reference
# pool = "tank" and set `disko.devices.zpool.tank.mode` accordingly
# (e.g. "mirror", "raidz1", "raidz2").
{lib, ...}: {
disko.devices = {
disk = {
# Boot disk - small SSD for OS
boot = {
device = lib.mkDefault "/dev/sda";
type = "disk";
content = {
type = "gpt";
partitions = {
ESP = {
size = "1G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = ["umask=0077"];
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};

# First data disk - member of the "tank" zpool.
# For mirrors or RAIDZ, copy this block as `tank1`, `tank2`, etc.,
# pointing each at a distinct device.
tank0 = {
device = lib.mkDefault "/dev/sdb";
type = "disk";
content = {
type = "gpt";
partitions = {
zfs = {
size = "100%";
content = {
type = "zfs";
pool = "tank";
};
};
};
};
};
};

zpool = {
# Main data pool. Disks are assigned via the partitions above
# (content.type = "zfs"; content.pool = "tank";).
# Change `mode` to "mirror", "raidz1", "raidz2" when adding more disks.
tank = {
type = "zpool";

rootFsOptions = {
compression = "zstd";
"com.sun:auto-snapshot" = "false";
};

options.ashift = "12";

datasets = {
# Container for all data
data = {
type = "zfs_fs";
mountpoint = "/tank/data";
options = {
compression = "zstd";
atime = "off";
};
};

# Paperless document storage
paperless = {
type = "zfs_fs";
mountpoint = "/var/lib/paperless";
options = {
compression = "zstd";
recordsize = "1M"; # Good for documents
atime = "off";
};
};

# Backups and snapshots
backup = {
type = "zfs_fs";
mountpoint = "/tank/backup";
options = {
compression = "zstd";
atime = "off";
};
};

# General media storage
media = {
type = "zfs_fs";
mountpoint = "/tank/media";
options = {
compression = "zstd";
recordsize = "1M";
atime = "off";
};
};
};
};
};
};
}
50 changes: 50 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,56 @@
];
};

# NAS - Network Attached Storage with ZFS and paperless-ngx
"type-nas" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = inputs // {inherit inputs;};
modules = [
configuration
./modules
./modules/nixos/base.nix
home-manager.nixosModules.home-manager
{home-manager.sharedModules = [opnix.homeManagerModules.default];}

# Disk layout - ZFS for data redundancy
inputs.disko.nixosModules.disko
./disk-configs/zfs-nas.nix

# Machine type configuration (includes myConfig, hardware.facter, SSH keys)
./machine-types/server.nix

# NAS-specific services (paperless, ZFS support)
./targets/type-nas
];
};

# CATTLE CONFIGURATIONS - Generic machine types
# These require no hardware-configuration.nix!
# Use with: ./scripts/install-machine.sh <type> <host> <disk>

"type-desktop" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = inputs // {inherit inputs;};
modules = [
configuration
./modules
./modules/nixos/base.nix
home-manager.nixosModules.home-manager
{home-manager.sharedModules = [opnix.homeManagerModules.default];}

# Disk layout
inputs.disko.nixosModules.disko
./disk-configs/zero.nix

# Machine type configuration (includes myConfig defaults and SSH keys)
./machine-types/desktop.nix

# Ghostty terminfo for SSH support
# https://github.com/ghostty-org/ghostty/discussions/5753
./modules/nixos/ghostty-terminfo.nix
];
};

# Foundation-based server configuration
# Minimal required fields: system architecture, SSH authorized keys
"type-server" = nixpkgs.lib.nixosSystem {
Expand Down
77 changes: 77 additions & 0 deletions targets/type-nas/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# type-nas - Network Attached Storage with document management
# Cattle configuration: ZFS storage + paperless-ngx for document archival
{
pkgs,
lib,
...
}: {
myConfig.autoUpgrade.flakeUrl = lib.mkForce "github:funkymonkeymonk/nix#type-nas";

# ZFS support
boot.supportedFilesystems = ["zfs"];
boot.zfs.forceImportRoot = false;

# ZFS kernel module
boot.kernelModules = ["zfs"];

# ZFS requires a unique 8-hex-digit host ID. Use a stable default here so
# the config evaluates deterministically; override per-host if needed.
networking.hostId = lib.mkDefault "8badf00d";

# Paperless-ngx document management
services.paperless = {
enable = true;
address = "0.0.0.0";
port = 28981;
dataDir = "/var/lib/paperless";

# Configure with sensible defaults
settings = {
PAPERLESS_OCR_LANGUAGE = "eng";
PAPERLESS_CONSUMER_RECURSIVE = "true";
PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS = "true";
};
};

# Ensure paperless can consume from a watched directory
# Note: ZFS dataset handles main storage, this creates the consume subdirectory
systemd.tmpfiles.rules = [
"d /var/lib/paperless/consume 0755 paperless paperless -"
];

# Open firewall for paperless web UI
networking.firewall.allowedTCPPorts = [28981];

# ZFS maintenance services
services.zfs.autoScrub.enable = true;
services.sanoid = {
enable = true;
templates = {
# Daily snapshots, keep for a month
daily = {
hourly = 24;
daily = 30;
monthly = 3;
autosnap = true;
autoprune = true;
};
};
datasets = {
"tank/paperless" = {
useTemplate = ["daily"];
};
"tank/data" = {
useTemplate = ["daily"];
};
};
};

environment.systemPackages = with pkgs; [
vim
htop
curl
zfs
sanoid
parted
];
}
Loading