organize
This commit is contained in:
64
modules/age-secrets.nix
Normal file
64
modules/age-secrets.nix
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
# Configure all agenix secrets
|
||||
age.secrets = {
|
||||
# ZFS encryption key
|
||||
zfs-key = {
|
||||
file = ../secrets/zfs-key.age;
|
||||
mode = "0400";
|
||||
owner = "root";
|
||||
group = "root";
|
||||
};
|
||||
|
||||
# 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";
|
||||
};
|
||||
|
||||
jellyfin-api-key = {
|
||||
file = ../secrets/jellyfin-api-key.age;
|
||||
mode = "0400";
|
||||
owner = "root";
|
||||
group = "root";
|
||||
};
|
||||
|
||||
slskd_env = {
|
||||
file = ../secrets/slskd_env.age;
|
||||
mode = "0400";
|
||||
owner = "root";
|
||||
group = "root";
|
||||
};
|
||||
|
||||
# Network configuration
|
||||
wg0-conf = {
|
||||
file = ../secrets/wg0.conf.age;
|
||||
mode = "0400";
|
||||
owner = "root";
|
||||
group = "root";
|
||||
};
|
||||
};
|
||||
}
|
||||
24
modules/hardware.nix
Normal file
24
modules/hardware.nix
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
service_configs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
boot.initrd.availableKernelModules = [
|
||||
"xhci_pci"
|
||||
"ahci"
|
||||
"usb_storage"
|
||||
"usbhid"
|
||||
"sd_mod"
|
||||
];
|
||||
boot.initrd.kernelModules = [ "dm-snapshot" ];
|
||||
boot.kernelModules = [ "kvm-amd" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
swapDevices = [ ];
|
||||
|
||||
hardware.cpu.amd.updateMicrocode = true;
|
||||
hardware.enableRedistributableFirmware = true;
|
||||
}
|
||||
31
modules/home.nix
Normal file
31
modules/home.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
home.stateVersion = "24.11";
|
||||
programs.fish = {
|
||||
enable = true;
|
||||
|
||||
interactiveShellInit = ''
|
||||
# disable greeting
|
||||
set fish_greeting
|
||||
|
||||
# pfetch on shell start (disable pkgs because of execution time)
|
||||
PF_INFO="ascii title os host kernel uptime memory editor wm" ${lib.getExe pkgs.pfetch-rs}
|
||||
'';
|
||||
|
||||
shellAliases =
|
||||
let
|
||||
eza = "${lib.getExe pkgs.eza} --color=always --group-directories-first";
|
||||
in
|
||||
{
|
||||
# from DistroTube's dot files: Changing "ls" to "eza"
|
||||
ls = "${eza} -al";
|
||||
la = "${eza} -a";
|
||||
ll = "${eza} -l";
|
||||
lt = "${eza} -aT";
|
||||
};
|
||||
};
|
||||
}
|
||||
52
modules/impermanence.nix
Normal file
52
modules/impermanence.nix
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
username,
|
||||
service_configs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
environment.persistence."/persistent" = {
|
||||
hideMounts = true;
|
||||
directories = [
|
||||
"/var/log"
|
||||
"/var/lib/systemd/coredump"
|
||||
"/var/lib/nixos"
|
||||
|
||||
"/var/lib/systemd/timers"
|
||||
];
|
||||
|
||||
files = [
|
||||
# SSH host keys
|
||||
"/etc/ssh/ssh_host_ed25519_key"
|
||||
"/etc/ssh/ssh_host_ed25519_key.pub"
|
||||
"/etc/ssh/ssh_host_rsa_key"
|
||||
"/etc/ssh/ssh_host_rsa_key.pub"
|
||||
|
||||
# Machine ID
|
||||
"/etc/machine-id"
|
||||
|
||||
# ZFS cache
|
||||
"/etc/zfs/zpool.cache"
|
||||
];
|
||||
|
||||
users.${username} = {
|
||||
files = [
|
||||
".local/share/fish/fish_history"
|
||||
];
|
||||
};
|
||||
|
||||
users.root = {
|
||||
home = "/root";
|
||||
|
||||
files = [
|
||||
".local/share/fish/fish_history"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /etc 755 root"
|
||||
];
|
||||
}
|
||||
158
modules/lib.nix
Normal file
158
modules/lib.nix
Normal file
@@ -0,0 +1,158 @@
|
||||
{
|
||||
inputs,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
inputs.nixpkgs.lib.extend (
|
||||
final: prev:
|
||||
let
|
||||
lib = prev;
|
||||
in
|
||||
{
|
||||
# stolen from: https://stackoverflow.com/a/42398526
|
||||
optimizeWithFlags =
|
||||
pkg: flags:
|
||||
lib.overrideDerivation pkg (
|
||||
old:
|
||||
let
|
||||
newflags = lib.foldl' (acc: x: "${acc} ${x}") "" flags;
|
||||
oldflags = if (lib.hasAttr "NIX_CFLAGS_COMPILE" old) then "${old.NIX_CFLAGS_COMPILE}" else "";
|
||||
in
|
||||
{
|
||||
NIX_CFLAGS_COMPILE = "${oldflags} ${newflags}";
|
||||
# stdenv = pkgs.clang19Stdenv;
|
||||
}
|
||||
);
|
||||
|
||||
optimizePackage =
|
||||
pkg:
|
||||
final.optimizeWithFlags pkg [
|
||||
"-O3"
|
||||
"-march=znver3"
|
||||
"-mtune=znver3"
|
||||
];
|
||||
|
||||
vpnNamespaceOpenPort =
|
||||
port: service:
|
||||
{ ... }:
|
||||
{
|
||||
vpnNamespaces.wg = {
|
||||
portMappings = [
|
||||
{
|
||||
from = port;
|
||||
to = port;
|
||||
}
|
||||
];
|
||||
|
||||
openVPNPorts = [
|
||||
{
|
||||
port = port;
|
||||
protocol = "both";
|
||||
}
|
||||
];
|
||||
};
|
||||
systemd.services.${service}.vpnConfinement = {
|
||||
enable = true;
|
||||
vpnNamespace = "wg";
|
||||
};
|
||||
};
|
||||
|
||||
serviceMountWithZpool =
|
||||
serviceName: zpool: dirs:
|
||||
{ pkgs, config, ... }:
|
||||
{
|
||||
systemd.services."${serviceName}-mounts" = {
|
||||
wants = [ "zfs.target" ] ++ lib.optionals (zpool != "") [ "zfs-import-${zpool}.service" ];
|
||||
after = lib.optionals (zpool != "") [ "zfs-import-${zpool}.service" ];
|
||||
before = [ "${serviceName}.service" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecStart = [
|
||||
(lib.getExe (
|
||||
pkgs.writeShellApplication {
|
||||
name = "ensure-zfs-mounts-with-pool-${serviceName}-${zpool}";
|
||||
runtimeInputs = with pkgs; [
|
||||
gawk
|
||||
coreutils
|
||||
config.boot.zfs.package
|
||||
];
|
||||
|
||||
text = ''
|
||||
set -euo pipefail
|
||||
|
||||
echo "Ensuring ZFS mounts for service: ${serviceName} (pool: ${zpool})"
|
||||
echo "Directories: ${lib.strings.concatStringsSep ", " dirs}"
|
||||
|
||||
# Validate mounts exist (ensureZfsMounts already has proper PATH)
|
||||
${lib.getExe pkgs.ensureZfsMounts} ${lib.strings.concatStringsSep " " dirs}
|
||||
|
||||
# Additional runtime check: verify paths are on correct zpool
|
||||
${lib.optionalString (zpool != "") ''
|
||||
echo "Verifying ZFS mountpoints are on pool '${zpool}'..."
|
||||
|
||||
if ! zfs_list_output=$(zfs list -H -o name,mountpoint 2>&1); then
|
||||
echo "ERROR: Failed to query ZFS datasets: $zfs_list_output" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2043
|
||||
for target in ${lib.strings.concatStringsSep " " dirs}; do
|
||||
echo "Checking: $target"
|
||||
|
||||
# Find dataset that has this mountpoint
|
||||
dataset=$(echo "$zfs_list_output" | awk -v target="$target" '$2 == target {print $1; exit}')
|
||||
|
||||
if [ -z "$dataset" ]; then
|
||||
echo "ERROR: No ZFS dataset found for mountpoint: $target" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract pool name from dataset (first part before /)
|
||||
actual_pool=$(echo "$dataset" | cut -d'/' -f1)
|
||||
|
||||
if [ "$actual_pool" != "${zpool}" ]; then
|
||||
echo "ERROR: ZFS pool mismatch for $target" >&2
|
||||
echo " Expected pool: ${zpool}" >&2
|
||||
echo " Actual pool: $actual_pool" >&2
|
||||
echo " Dataset: $dataset" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$target is on $dataset (pool: $actual_pool)"
|
||||
done
|
||||
|
||||
echo "All paths verified successfully on pool '${zpool}'"
|
||||
''}
|
||||
|
||||
echo "Mount validation completed for ${serviceName} (pool: ${zpool})"
|
||||
'';
|
||||
}
|
||||
))
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.${serviceName} = {
|
||||
wants = [
|
||||
"${serviceName}-mounts.service"
|
||||
];
|
||||
after = [
|
||||
"${serviceName}-mounts.service"
|
||||
];
|
||||
requires = [
|
||||
"${serviceName}-mounts.service"
|
||||
];
|
||||
};
|
||||
|
||||
# assert that the pool is even enabled
|
||||
#assertions = lib.optionals (zpool != "") [
|
||||
# {
|
||||
# assertion = builtins.elem zpool config.boot.zfs.extraPools;
|
||||
# message = "${zpool} is not enabled in `boot.zfs.extraPools`";
|
||||
# }
|
||||
#];
|
||||
};
|
||||
}
|
||||
)
|
||||
49
modules/no-rgb.nix
Normal file
49
modules/no-rgb.nix
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
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;
|
||||
package = pkgs.openrgb-with-all-plugins;
|
||||
motherboard = "amd";
|
||||
};
|
||||
|
||||
services.udev.packages = [ pkgs.openrgb-with-all-plugins ];
|
||||
hardware.i2c.enable = true;
|
||||
}
|
||||
46
modules/overlays.nix
Normal file
46
modules/overlays.nix
Normal file
@@ -0,0 +1,46 @@
|
||||
final: prev: {
|
||||
ensureZfsMounts = prev.writeShellApplication {
|
||||
name = "zfsEnsureMounted";
|
||||
runtimeInputs = with prev; [
|
||||
zfs
|
||||
gawk
|
||||
coreutils
|
||||
];
|
||||
|
||||
text = ''
|
||||
#!/bin/sh
|
||||
|
||||
if [[ "$#" -eq "0" ]]; then
|
||||
echo "no arguments passed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MOUNTED=$(zfs list -o mountpoint,mounted -H | awk '$NF == "yes" {NF--; print}')
|
||||
|
||||
MISSING=""
|
||||
for target in "$@"; do
|
||||
if ! grep -Fxq "$target" <<< "$MOUNTED"; then
|
||||
MISSING="$MISSING $target"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -n "$MISSING" ]]; then
|
||||
echo "FAILURE, missing:$MISSING" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
reflac = prev.writeShellApplication {
|
||||
name = "reflac";
|
||||
runtimeInputs = with prev; [ flac ];
|
||||
excludeShellChecks = [ "2086" ];
|
||||
|
||||
text = builtins.readFile (
|
||||
prev.fetchurl {
|
||||
url = "https://raw.githubusercontent.com/chungy/reflac/refs/heads/master/reflac";
|
||||
sha256 = "61c6cc8be3d276c6714e68b55e5de0e6491f50bbf195233073dbce14a1e278a7";
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
41
modules/secureboot.nix
Normal file
41
modules/secureboot.nix
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
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
|
||||
# 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"
|
||||
chown -R root:wheel ${config.boot.lanzaboote.pkiBundle}
|
||||
chmod -R 500 ${config.boot.lanzaboote.pkiBundle}
|
||||
else
|
||||
echo "Extracting secureboot keys from agenix"
|
||||
rm -fr ${config.boot.lanzaboote.pkiBundle} || true
|
||||
mkdir -p ${config.boot.lanzaboote.pkiBundle}
|
||||
${pkgs.gnutar}/bin/tar xf ${config.age.secrets.secureboot-tar.path} -C ${config.boot.lanzaboote.pkiBundle}
|
||||
chown -R root:wheel ${config.boot.lanzaboote.pkiBundle}
|
||||
chmod -R 500 ${config.boot.lanzaboote.pkiBundle}
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
22
modules/usb-secrets.nix
Normal file
22
modules/usb-secrets.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
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" ];
|
||||
}
|
||||
92
modules/zfs.nix
Normal file
92
modules/zfs.nix
Normal file
@@ -0,0 +1,92 @@
|
||||
{
|
||||
config,
|
||||
service_configs,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
# DO NOT CHANGE
|
||||
# path is set via a zfs property
|
||||
zfs-key = "/etc/zfs-key";
|
||||
in
|
||||
{
|
||||
system.activationScripts = {
|
||||
# Copy decrypted ZFS key from agenix to expected location
|
||||
# /etc is on tmpfs due to impermanence, so no persistent storage risk
|
||||
"zfs-key".text = ''
|
||||
#!/bin/sh
|
||||
rm -f ${zfs-key} || true
|
||||
cp ${config.age.secrets.zfs-key.path} ${zfs-key}
|
||||
chmod 0400 ${zfs-key}
|
||||
chown root:root ${zfs-key}
|
||||
'';
|
||||
};
|
||||
|
||||
boot.zfs.package = pkgs.zfs;
|
||||
boot.initrd.kernelModules = [ "zfs" ];
|
||||
|
||||
boot.kernelParams =
|
||||
let
|
||||
gb = 20;
|
||||
mb = gb * 1000;
|
||||
kb = mb * 1000;
|
||||
b = kb * 1000;
|
||||
in
|
||||
[
|
||||
"zfs.zfs_arc_max=${builtins.toString b}"
|
||||
];
|
||||
|
||||
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_hdds}" = {
|
||||
recursive = true;
|
||||
autoprune = true;
|
||||
autosnap = true;
|
||||
hourly = 0;
|
||||
daily = 0;
|
||||
monthly = 0;
|
||||
yearly = 0;
|
||||
};
|
||||
};
|
||||
|
||||
services.zfs = {
|
||||
autoScrub.enable = true;
|
||||
trim.enable = true;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user