phase 2: move modules/ (server-*, desktop-*, shared); drop dotfiles no-rgb (superseded)

This commit is contained in:
primary
2026-04-18 00:47:56 -04:00
parent 999ed05d9f
commit 30d8cf4c99
13 changed files with 0 additions and 43 deletions

View File

@@ -1,26 +0,0 @@
{ hostname, ... }:
{
# speed up boot times (by about three seconds)
systemd.services.NetworkManager-wait-online.enable = false;
networking = {
hostName = hostname;
networkmanager = {
enable = true;
appendNameservers = [
"1.1.1.1"
"9.9.9.9"
];
wifi = {
scanRandMacAddress = true;
# fix suspend issue
# powersave = false;
};
ensureProfiles.profiles = import ./secrets/wifi-passwords.nix;
};
};
}

View File

@@ -1,43 +0,0 @@
{ pkgs, lib, ... }:
{
systemd.services.no-rgb =
let
no-rgb = (
pkgs.writeShellApplication {
name = "no-rgb";
runtimeInputs = with pkgs; [
openrgb
coreutils
gnugrep
];
text = ''
#!/bin/sh
set -e
NUM_DEVICES=$(openrgb --noautoconnect --list-devices | grep -cE '^[0-9]+: ')
for i in $(seq 0 $((NUM_DEVICES - 1))); do
openrgb --noautoconnect --device "$i" --mode direct --color 000000
done
'';
}
);
in
{
description = "disable rgb";
serviceConfig = {
ExecStart = "${lib.getExe no-rgb}";
Type = "oneshot";
};
wantedBy = [ "multi-user.target" ];
};
services.hardware.openrgb.enable = true;
services.udev.packages = [ pkgs.openrgb ];
hardware.i2c.enable = true;
environment.systemPackages = with pkgs; [
openrgb-with-all-plugins
];
}

View File

@@ -1,28 +0,0 @@
{
pkgs,
config,
lib,
...
}:
{
nixpkgs.config.allowUnfreePredicate =
pkg:
builtins.elem (lib.getName pkg) [
"steam"
"steam-original"
"steam-unwrapped"
"steam-run"
];
programs.steam = {
enable = true;
extraCompatPackages = with pkgs; [ proton-ge-bin ];
};
environment.systemPackages = with pkgs; [
steamtinkerlaunch
mangohud
goverlay
yad
];
}

View File

@@ -1,39 +0,0 @@
{
pkgs,
username,
lib,
...
}:
{
# android virtualization
virtualisation.waydroid = {
enable = true;
# https://github.com/NixOS/nixpkgs/pull/466473
package = pkgs.waydroid-nftables;
};
programs.virt-manager.enable = true;
users.groups.libvirtd.members = [ username ];
virtualisation.libvirtd = {
enable = true;
package = pkgs.libvirt;
};
virtualisation.spiceUSBRedirection.enable = true;
users.users."${username}".extraGroups = [ "libvirtd" ];
# boot.kernelPatches = [
# {
# name = "undetected-kvm";
# patch = pkgs.fetchurl {
# url = "https://raw.githubusercontent.com/Scrut1ny/Hypervisor-Phantom/d09d66813570704e2b05440f290d6f9bdf2d26c7/Hypervisor-Phantom/patches/Kernel/linux-6.13-svm.patch";
# sha256 = "zz18xerutulLGzlHhnu26WCY8rVQXApyeoDtCjbejIk=";
# };
# }
# ];
}

View File

@@ -1,203 +0,0 @@
{
config,
lib,
pkgs,
inputs,
...
}:
{
imports = [
inputs.agenix.nixosModules.default
];
# Configure all agenix secrets
age.secrets = {
# ZFS encryption key
# path is set to /etc/zfs-key to match the ZFS dataset keylocation property
zfs-key = {
file = ../secrets/zfs-key.age;
mode = "0400";
owner = "root";
group = "root";
path = "/etc/zfs-key";
};
# Secureboot keys archive
secureboot-tar = {
file = ../secrets/secureboot.tar.age;
mode = "0400";
owner = "root";
group = "root";
};
# System passwords
hashedPass = {
file = ../secrets/hashedPass.age;
mode = "0400";
owner = "root";
group = "root";
};
# Service authentication
caddy_auth = {
file = ../secrets/caddy_auth.age;
mode = "0400";
owner = "caddy";
group = "caddy";
};
# Njalla API token (NJALLA_API_TOKEN=...) for Caddy DNS-01 challenge
njalla-api-token-env = {
file = ../secrets/njalla-api-token-env.age;
mode = "0400";
owner = "caddy";
group = "caddy";
};
# ddns-updater config.json with Njalla provider credentials
ddns-updater-config = {
file = ../secrets/ddns-updater-config.age;
mode = "0400";
owner = "ddns-updater";
group = "ddns-updater";
};
jellyfin-api-key = {
file = ../secrets/jellyfin-api-key.age;
mode = "0400";
owner = "root";
group = "root";
};
slskd_env = {
file = ../secrets/slskd_env.age;
mode = "0500";
owner = config.services.slskd.user;
group = config.services.slskd.group;
};
# Network configuration
wg0-conf = {
file = ../secrets/wg0.conf.age;
mode = "0400";
owner = "root";
group = "root";
};
# ntfy-alerts secrets (group-readable for CI runner notifications)
ntfy-alerts-topic = {
file = ../secrets/ntfy-alerts-topic.age;
mode = "0440";
owner = "root";
group = "gitea-runner";
};
ntfy-alerts-token = {
file = ../secrets/ntfy-alerts-token.age;
mode = "0440";
owner = "root";
group = "gitea-runner";
};
# Firefox Sync server secrets (SYNC_MASTER_SECRET)
firefox-syncserver-env = {
file = ../secrets/firefox-syncserver-env.age;
mode = "0400";
};
# MollySocket env (MOLLY_VAPID_PRIVKEY + MOLLY_ALLOWED_UUIDS)
mollysocket-env = {
file = ../secrets/mollysocket-env.age;
mode = "0400";
};
# Murmur (Mumble) server password
murmur-password-env = {
file = ../secrets/murmur-password-env.age;
mode = "0400";
owner = "murmur";
group = "murmur";
};
# Coturn static auth secret
coturn-auth-secret = {
file = ../secrets/coturn-auth-secret.age;
mode = "0400";
owner = "turnserver";
group = "turnserver";
};
# Matrix (continuwuity) registration token
matrix-reg-token = {
file = ../secrets/matrix-reg-token.age;
mode = "0400";
owner = "continuwuity";
group = "continuwuity";
};
# Matrix (continuwuity) TURN secret — same secret as coturn-auth-secret,
# decrypted separately so continuwuity can read it with its own ownership
matrix-turn-secret = {
file = ../secrets/coturn-auth-secret.age;
mode = "0400";
owner = "continuwuity";
group = "continuwuity";
};
# CI deploy SSH key
ci-deploy-key = {
file = ../secrets/ci-deploy-key.age;
mode = "0400";
owner = "gitea-runner";
group = "gitea-runner";
};
# Git-crypt symmetric key for dotfiles repo
git-crypt-key-dotfiles = {
file = ../secrets/git-crypt-key-dotfiles.age;
mode = "0400";
owner = "gitea-runner";
group = "gitea-runner";
};
# Git-crypt symmetric key for server-config repo
git-crypt-key-server-config = {
file = ../secrets/git-crypt-key-server-config.age;
mode = "0400";
owner = "gitea-runner";
group = "gitea-runner";
};
# Gitea Actions runner registration token
gitea-runner-token = {
file = ../secrets/gitea-runner-token.age;
mode = "0400";
owner = "gitea-runner";
group = "gitea-runner";
};
# llama-cpp API key for bearer token auth
llama-cpp-api-key = {
file = ../secrets/llama-cpp-api-key.age;
mode = "0400";
owner = "root";
group = "root";
};
# Harmonia binary cache signing key
harmonia-sign-key = {
file = ../secrets/harmonia-sign-key.age;
mode = "0400";
owner = "harmonia";
group = "harmonia";
};
# Caddy basic auth for nix binary cache (separate from main caddy_auth)
nix-cache-auth = {
file = ../secrets/nix-cache-auth.age;
mode = "0400";
owner = "caddy";
group = "caddy";
};
};
}

View File

@@ -1,71 +0,0 @@
{
config,
lib,
pkgs,
username,
service_configs,
inputs,
...
}:
{
imports = [
inputs.impermanence.nixosModules.impermanence
];
environment.persistence."/persistent" = {
hideMounts = true;
directories = [
"/var/log"
"/var/lib/systemd/coredump"
"/var/lib/nixos"
"/var/lib/systemd/timers"
# ZFS cache directory - persisting the directory instead of the file
# avoids "device busy" errors when ZFS atomically updates the cache
"/etc/zfs"
"/var/lib/gitea-runner"
];
files = [
# Machine ID
"/etc/machine-id"
];
users.${username} = {
files = [
".local/share/fish/fish_history"
];
};
users.root = {
files = [
".local/share/fish/fish_history"
];
};
};
# Store SSH host keys directly in /persistent to survive tmpfs root wipes.
# This is more reliable than bind mounts for service-generated files.
services.openssh.hostKeys = [
{
path = "/persistent/etc/ssh/ssh_host_ed25519_key";
type = "ed25519";
}
{
path = "/persistent/etc/ssh/ssh_host_rsa_key";
type = "rsa";
bits = 4096;
}
];
# Enforce root ownership on /persistent/etc. The impermanence activation
# script copies ownership from /persistent/etc to /etc via
# `chown --reference`. If /persistent/etc ever gets non-root ownership,
# sshd StrictModes rejects /etc/ssh/authorized_keys.d/root and root SSH
# breaks while non-root users still work.
# Use "z" (set ownership, non-recursive) not "d" (create only, no-op on existing).
systemd.tmpfiles.rules = [
"z /persistent/etc 0755 root root"
];
}

View File

@@ -1,66 +0,0 @@
{
config,
lib,
pkgs,
...
}:
{
systemd.services.no-rgb =
let
no-rgb = (
pkgs.writeShellApplication {
name = "no-rgb";
runtimeInputs = with pkgs; [
openrgb
coreutils
gnugrep
];
text = ''
# Retry loop to wait for hardware to be ready
NUM_DEVICES=0
for attempt in 1 2 3 4 5; do
DEVICE_LIST=$(openrgb --noautoconnect --list-devices 2>/dev/null) || DEVICE_LIST=""
NUM_DEVICES=$(echo "$DEVICE_LIST" | grep -cE '^[0-9]+: ') || NUM_DEVICES=0
if [ "$NUM_DEVICES" -gt 0 ]; then
break
fi
if [ "$attempt" -lt 5 ]; then
sleep 2
fi
done
# If no devices found after retries, exit gracefully
if [ "$NUM_DEVICES" -eq 0 ]; then
exit 0
fi
# Disable RGB on each device
for i in $(seq 0 $((NUM_DEVICES - 1))); do
openrgb --noautoconnect --device "$i" --mode direct --color 000000 || true
done
'';
}
);
in
{
description = "disable rgb";
after = [ "systemd-udev-settle.service" ];
serviceConfig = {
ExecStart = lib.getExe no-rgb;
Type = "oneshot";
Restart = "on-failure";
RestartSec = 5;
};
wantedBy = [ "multi-user.target" ];
};
services.hardware.openrgb = {
enable = true;
package = pkgs.openrgb-with-all-plugins;
motherboard = "amd";
};
services.udev.packages = [ pkgs.openrgb-with-all-plugins ];
hardware.i2c.enable = true;
}

View File

@@ -1,132 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.ntfyAlerts;
curl = "${pkgs.curl}/bin/curl";
hostname = config.networking.hostName;
# Build the curl auth args as a proper bash array fragment
authCurlArgs =
if cfg.tokenFile != null then
''
if [ -f "${cfg.tokenFile}" ]; then
TOKEN=$(cat "${cfg.tokenFile}" 2>/dev/null || echo "")
if [ -n "$TOKEN" ]; then
AUTH_ARGS=(-H "Authorization: Bearer $TOKEN")
fi
fi
''
else
"";
# Systemd failure alert script
systemdAlertScript = pkgs.writeShellScript "ntfy-systemd-alert" ''
set -euo pipefail
UNIT_NAME="$1"
SERVER_URL="${cfg.serverUrl}"
TOPIC=$(cat "${cfg.topicFile}" 2>/dev/null | tr -d '[:space:]')
if [ -z "$TOPIC" ]; then
echo "ERROR: Could not read topic from ${cfg.topicFile}"
exit 1
fi
# Get journal output for context
JOURNAL_OUTPUT=$(${pkgs.systemd}/bin/journalctl -u "$UNIT_NAME" -n 15 --no-pager 2>/dev/null || echo "No journal output available")
# Build auth args
AUTH_ARGS=()
${authCurlArgs}
# Send notification
${curl} -sf --max-time 15 -X POST \
"$SERVER_URL/$TOPIC" \
-H "Title: [${hostname}] Service failed: $UNIT_NAME" \
-H "Priority: high" \
-H "Tags: warning" \
"''${AUTH_ARGS[@]}" \
-d "$JOURNAL_OUTPUT" || true
'';
in
{
options.services.ntfyAlerts = {
enable = lib.mkEnableOption "ntfy push notifications for system alerts";
serverUrl = lib.mkOption {
type = lib.types.str;
description = "The ntfy server URL (e.g. https://ntfy.example.com)";
example = "https://ntfy.example.com";
};
topicFile = lib.mkOption {
type = lib.types.path;
description = "Path to a file containing the ntfy topic name to publish alerts to.";
example = "/run/agenix/ntfy-alerts-topic";
};
tokenFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Path to a file containing the ntfy auth token.
If set, uses Authorization: Bearer header for authentication.
'';
example = "/run/secrets/ntfy-token";
};
};
config = lib.mkIf cfg.enable {
# Per-service OnFailure for monitored services
systemd.services = {
"ntfy-alert@" = {
description = "Send ntfy notification for failed service %i";
unitConfig.OnFailure = lib.mkForce "";
serviceConfig = {
Type = "oneshot";
ExecStart = "${systemdAlertScript} %i";
TimeoutSec = 30;
};
};
# TODO: sanoid's ExecStartPre runs `zfs allow` which blocks on TXG sync;
# on the hdds pool (slow spinning disks + large async frees) this causes
# 30+ minute hangs and guaranteed timeouts. Suppress until we fix sanoid
# to run as root without `zfs allow`. See: nixpkgs#72060, openzfs/zfs#14180
"sanoid".unitConfig.OnFailure = lib.mkForce "";
};
# Global OnFailure drop-in for all services
systemd.packages = [
(pkgs.writeTextDir "etc/systemd/system/service.d/onfailure.conf" ''
[Unit]
OnFailure=ntfy-alert@%p.service
'')
# Sanoid-specific drop-in to override the global OnFailure (see TODO above)
(pkgs.writeTextDir "etc/systemd/system/sanoid.service.d/onfailure.conf" ''
[Unit]
OnFailure=
'')
];
# ZED (ZFS Event Daemon) ntfy notification settings
services.zfs.zed = {
enableMail = false;
settings = {
ZED_NTFY_URL = cfg.serverUrl;
ZED_NTFY_TOPIC = "$(cat ${cfg.topicFile} | tr -d '[:space:]')";
ZED_NTFY_ACCESS_TOKEN = lib.mkIf (cfg.tokenFile != null) "$(cat ${cfg.tokenFile})";
ZED_NOTIFY_VERBOSE = true;
};
};
};
}

View File

@@ -1,41 +0,0 @@
{
...
}:
{
powerManagement = {
enable = true;
cpuFreqGovernor = "powersave";
};
# Always-on server: disable all sleep targets.
systemd.targets = {
sleep.enable = false;
suspend.enable = false;
hibernate.enable = false;
hybrid-sleep.enable = false;
};
boot.kernelParams = [
# Disable NMI watchdog at boot. Eliminates periodic perf-counter interrupts
# across all cores (~1 W). Safe: apcupsd provides hardware hang detection
# via UPS, and softlockup watchdog remains active.
"nmi_watchdog=0"
# Route kernel work items to already-busy CPUs rather than waking idle ones.
# Reduces C-state exit frequency at the cost of slightly higher latency on
# work items -- irrelevant for a server whose latency-sensitive paths are
# all in userspace (caddy, jellyfin).
"workqueue.power_efficient=1"
];
boot.kernel.sysctl = {
# Belt-and-suspenders: also set via boot param, but sysctl ensures it
# stays off if anything re-enables it at runtime.
"kernel.nmi_watchdog" = 0;
};
# Server has no audio consumers. Power-gate the HDA codec at module load.
boot.extraModprobeConfig = ''
options snd_hda_intel power_save=1 power_save_controller=Y
'';
}

View File

@@ -1,42 +0,0 @@
{
config,
lib,
pkgs,
...
}:
{
boot = {
loader.systemd-boot.enable = lib.mkForce false;
lanzaboote = {
enable = true;
# needed to be in `/etc/secureboot` for sbctl to work
pkiBundle = "/etc/secureboot";
};
};
system.activationScripts = {
# extract secureboot keys from agenix-decrypted tar
"secureboot-keys" = {
deps = [ "agenix" ];
text = ''
#!/bin/sh
(
umask 077
# Check if keys already exist (e.g., from disko-install)
if [[ -d ${config.boot.lanzaboote.pkiBundle} && -f ${config.boot.lanzaboote.pkiBundle}/db.key ]]; then
echo "Secureboot keys already present, skipping extraction"
else
echo "Extracting secureboot keys from agenix"
rm -fr ${config.boot.lanzaboote.pkiBundle} || true
install -d -o root -g wheel -m 0500 ${config.boot.lanzaboote.pkiBundle}
${pkgs.gnutar}/bin/tar xf ${config.age.secrets.secureboot-tar.path} -C ${config.boot.lanzaboote.pkiBundle}
fi
chown -R root:wheel ${config.boot.lanzaboote.pkiBundle}
chmod -R 500 ${config.boot.lanzaboote.pkiBundle}
)
'';
};
};
}

View File

@@ -1,120 +0,0 @@
{
config,
lib,
pkgs,
...
}:
{
# memory allocator
# BREAKS REDIS-IMMICH
# environment.memoryAllocator.provider = "graphene-hardened";
# disable coredumps
systemd.coredump.enable = false;
# Needed for Nix sandbox UID/GID mapping inside derivation builds.
# See https://github.com/NixOS/nixpkgs/issues/287194
security.unprivilegedUsernsClone = true;
# Disable kexec to prevent replacing the running kernel at runtime.
security.protectKernelImage = true;
# Kernel hardening boot parameters. These recover most of the runtime-
# configurable protections that the linux-hardened patchset provided.
boot.kernelParams = [
# Zero all page allocator pages on free / alloc. Prevents info leaks
# and use-after-free from seeing stale data. Modest CPU overhead.
"init_on_alloc=1"
"init_on_free=1"
# Prevent SLUB allocator from merging caches with similar size/flags.
# Keeps different kernel object types in separate slabs, making heap
# exploitation (type confusion, spray, use-after-free) significantly harder.
"slab_nomerge"
# Randomize order of pages returned by the buddy allocator.
"page_alloc.shuffle=1"
# Disable debugfs entirely (exposes kernel internals).
"debugfs=off"
# Disable legacy vsyscall emulation (unused by any modern glibc).
"vsyscall=none"
# Strict IOMMU TLB invalidation (no batching). Prevents DMA-capable
# devices from accessing stale mappings after unmap.
"iommu.strict=1"
];
boot.kernel.sysctl = {
# Immediately reboot on kernel oops (don't leave a compromised
# kernel running). Negative value = reboot without delay.
"kernel.panic" = -1;
# Hide kernel pointers from all processes, including CAP_SYSLOG.
# Prevents info leaks used to defeat KASLR.
"kernel.kptr_restrict" = 2;
# Disable bpf() JIT compiler (eliminates JIT spray attack vector).
"net.core.bpf_jit_enable" = false;
# Disable ftrace (kernel function tracer) at runtime.
"kernel.ftrace_enabled" = false;
# Strict reverse-path filtering: drop packets arriving on an interface
# where the source address isn't routable back via that interface.
"net.ipv4.conf.all.rp_filter" = 1;
"net.ipv4.conf.default.rp_filter" = 1;
"net.ipv4.conf.all.log_martians" = true;
"net.ipv4.conf.default.log_martians" = true;
# Ignore ICMP redirects (prevents route table poisoning).
"net.ipv4.conf.all.accept_redirects" = false;
"net.ipv4.conf.all.secure_redirects" = false;
"net.ipv4.conf.default.accept_redirects" = false;
"net.ipv4.conf.default.secure_redirects" = false;
"net.ipv6.conf.all.accept_redirects" = false;
"net.ipv6.conf.default.accept_redirects" = false;
# Don't send ICMP redirects (we are not a router).
"net.ipv4.conf.all.send_redirects" = false;
"net.ipv4.conf.default.send_redirects" = false;
# Ignore broadcast ICMP (SMURF amplification mitigation).
"net.ipv4.icmp_echo_ignore_broadcasts" = true;
# Filesystem hardening: prevent hardlink/symlink-based attacks.
# protected_hardlinks/symlinks: block unprivileged creation of hard/symlinks
# to files the user doesn't own (prevents TOCTOU privilege escalation).
# protected_fifos/regular (level 2): restrict opening FIFOs and regular files
# in world-writable sticky directories to owner/group match only.
# Also required for systemd-tmpfiles to chmod hardlinked files.
"fs.protected_hardlinks" = true;
"fs.protected_symlinks" = true;
"fs.protected_fifos" = 2;
"fs.protected_regular" = 2;
};
services = {
dbus.implementation = "broker";
/*
logrotate.enable = true;
journald = {
storage = "volatile"; # Store logs in memory
upload.enable = false; # Disable remote log upload (the default)
extraConfig = ''
SystemMaxUse=500M
SystemMaxFileSize=50M
'';
};
*/
};
services.fail2ban = {
enable = true;
# Use iptables actions for compatibility
banaction = "iptables-multiport";
banaction-allports = "iptables-allports";
};
}

View File

@@ -1,22 +0,0 @@
{
config,
lib,
pkgs,
...
}:
{
# Mount USB secrets drive via fileSystems
fileSystems."/mnt/usb-secrets" = {
device = "/dev/disk/by-label/SECRETS";
fsType = "vfat";
options = [
"ro"
"uid=root"
"gid=root"
"umask=377"
];
neededForBoot = true;
};
age.identityPaths = [ "/mnt/usb-secrets/usb-secrets-key" ];
}

View File

@@ -1,127 +0,0 @@
{
config,
lib,
service_configs,
pkgs,
...
}:
let
# Total RAM in bytes (from /proc/meminfo: 65775836 KiB).
totalRamBytes = 65775836 * 1024;
# Hugepage reservations that the kernel carves out before ZFS can use them.
hugepages2mBytes = service_configs.hugepages_2m.total_pages * 2 * 1024 * 1024;
hugepages1gBytes = 3 * 1024 * 1024 * 1024; # 3x 1G pages for RandomX (xmrig.nix)
totalHugepageBytes = hugepages2mBytes + hugepages1gBytes;
# ARC max: 60% of RAM remaining after hugepages. Leaves headroom for
# application RSS (PostgreSQL, qBittorrent, Jellyfin, Grafana, etc.),
# kernel slabs, and page cache.
arcMaxBytes = (totalRamBytes - totalHugepageBytes) * 60 / 100;
in
{
boot.zfs.package = pkgs.zfs_2_4;
boot.initrd.kernelModules = [ "zfs" ];
boot.kernelParams = [
# 120s TXG timeout: batch more dirty data per transaction group so the
# HDD pool (hdds) writes larger, sequential I/Os instead of many small syncs.
# This is a global setting (no per-pool control); the SSD pool (tank) syncs
# infrequently but handles it fine since SSDs don't suffer from seek overhead.
"zfs.zfs_txg_timeout=120"
# Cap ARC to prevent it from claiming memory reserved for hugepages.
# Without this, ZFS auto-sizes c_max to ~62 GiB on a 64 GiB system,
# ignoring the 11.5 GiB of hugepage reservations.
"zfs.zfs_arc_max=${toString arcMaxBytes}"
# vdev I/O scheduler: feed more concurrent reads to the block scheduler so
# mq-deadline has a larger pool of requests to sort and merge into elevator sweeps.
# Default async_read_max is 3 — far too few for effective coalescence.
# 32 was empirically optimal (64 overwhelmed the drives, 3 gave near-zero merges).
"zfs.zfs_vdev_async_read_max_active=32"
"zfs.zfs_vdev_async_read_min_active=4"
# Merge reads within 128 KiB of each other (default 32 KiB). On HDDs, reading a
# 128 KiB gap is far cheaper than a mechanical seek (~8 ms).
"zfs.zfs_vdev_read_gap_limit=131072"
# Allow ZFS to aggregate I/Os up to 4 MiB (default 1 MiB), matching the
# libtorrent piece extent size for larger sequential disk operations.
"zfs.zfs_vdev_aggregation_limit=4194304"
];
boot.supportedFilesystems = [ "zfs" ];
boot.zfs.extraPools = [
service_configs.zpool_ssds
service_configs.zpool_hdds
];
services.sanoid = {
enable = true;
datasets."${service_configs.zpool_ssds}" = {
recursive = true;
autoprune = true;
autosnap = true;
hourly = 5;
daily = 7;
monthly = 3;
yearly = 0;
};
datasets."${service_configs.zpool_ssds}/services/sql" = {
recursive = true;
autoprune = true;
autosnap = true;
hourly = 12;
daily = 2;
monthly = 0;
yearly = 0;
};
datasets."${service_configs.zpool_ssds}/services/jellyfin/cache" = {
recursive = true;
autoprune = true;
autosnap = true;
hourly = 0;
daily = 0;
monthly = 0;
yearly = 0;
};
datasets."${service_configs.zpool_ssds}/services/monero" = {
recursive = true;
autoprune = true;
autosnap = true;
hourly = 0;
daily = 0;
monthly = 0;
yearly = 0;
};
datasets."${service_configs.zpool_ssds}/services/p2pool" = {
recursive = true;
autoprune = true;
autosnap = true;
hourly = 0;
daily = 0;
monthly = 0;
yearly = 0;
};
datasets."${service_configs.zpool_hdds}" = {
recursive = true;
autoprune = true;
autosnap = true;
hourly = 0;
daily = 0;
monthly = 0;
yearly = 0;
};
};
services.zfs = {
autoScrub.enable = true;
trim.enable = true;
};
}