Commit b50d7ae1132b

Vincent Demeester <vincent@sbr.pm>
2025-12-14 22:53:35
feat(homelab): Refactor NFS mounts and add ebook/audiobook tooling
- Centralize NFS mount configuration in reusable module - Enable rhea media access across all client systems consistently - Add Calibre for ebook management and audible-converter for audiobooks - Remove unused aria2 service in favor of transmission Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 parent 924fe09
systems/aix/hardware.nix
@@ -1,4 +1,8 @@
 _: {
+  imports = [
+    ../common/services/nfs-rhea-mounts.nix
+  ];
+
   fileSystems = {
     "/" = {
       device = "/dev/disk/by-label/NIXOS_SD";
@@ -11,4 +15,16 @@ _: {
       options = [ "noatime" ];
     };
   };
+
+  # NFS mounts from rhea
+  services.nfs-rhea-mounts = {
+    enable = true;
+    folders = [
+      "audiobooks"
+      "downloads"
+      "music"
+      "pictures"
+      "videos"
+    ];
+  };
 }
systems/aomi/extra.nix
@@ -32,8 +32,6 @@
   # Firewall is enabled in openshift-port-forward.nix
   # networking.firewall.enable = false;
 
-  boot.supportedFilesystems = [ "nfs" ];
-
   # TODO make it an option ? (otherwise I'll add it for all)
   users.users.vincent.linger = true;
 
systems/aomi/hardware.nix
@@ -11,6 +11,7 @@
 
     ../common/hardware/acpid.nix
     # ../common/hardware/bluetooth.nix
+    ../common/services/nfs-rhea-mounts.nix
   ];
 
   hardware = {
@@ -46,48 +47,14 @@
   swapDevices = [ { device = "/dev/disk/by-uuid/24da6a46-cd28-4bff-9220-6f449e3bd8b5"; } ];
 
   # NFS mounts from rhea
-  fileSystems."/net/rhea/music" = {
-    device = "rhea.sbr.pm:/music"; # NFSv4: path relative to fsid=0 (/neo)
-    fsType = "nfs";
-    options = [
-      "nfsvers=4.2" # Use NFSv4.2 for best performance
-      "x-systemd.automount" # Lazy-mount on first access
-      "noauto" # Don't mount at boot
-      "x-systemd.idle-timeout=600" # Auto-unmount after 10 min idle
-      "soft" # Don't hang if server unavailable
-      "timeo=14" # Timeout after 1.4s (14 * 0.1s)
-      "retrans=2" # Retry twice before timing out
-      "_netdev" # Wait for network before mounting
-    ];
-  };
-
-  fileSystems."/net/rhea/pictures" = {
-    device = "rhea.sbr.pm:/pictures";
-    fsType = "nfs";
-    options = [
-      "nfsvers=4.2"
-      "x-systemd.automount"
-      "noauto"
-      "x-systemd.idle-timeout=600"
-      "soft"
-      "timeo=14"
-      "retrans=2"
-      "_netdev"
-    ];
-  };
-
-  fileSystems."/net/rhea/videos" = {
-    device = "rhea.sbr.pm:/videos";
-    fsType = "nfs";
-    options = [
-      "nfsvers=4.2"
-      "x-systemd.automount"
-      "noauto"
-      "x-systemd.idle-timeout=600"
-      "soft"
-      "timeo=14"
-      "retrans=2"
-      "_netdev"
+  services.nfs-rhea-mounts = {
+    enable = true;
+    folders = [
+      "audiobooks"
+      "downloads"
+      "music"
+      "pictures"
+      "videos"
     ];
   };
 }
systems/common/services/nfs-rhea-mounts.nix
@@ -0,0 +1,57 @@
+# NFS mounts from rhea server
+# This module provides configurable NFS mounts for rhea's shared directories
+{
+  config,
+  lib,
+  ...
+}:
+let
+  cfg = config.services.nfs-rhea-mounts;
+in
+{
+  options.services.nfs-rhea-mounts = {
+    enable = lib.mkEnableOption "NFS mounts from rhea server";
+
+    folders = lib.mkOption {
+      type = lib.types.listOf lib.types.str;
+      default = [ ];
+      example = [
+        "audiobooks"
+        "music"
+        "pictures"
+        "videos"
+        "downloads"
+      ];
+      description = ''
+        List of folders to mount from rhea's /neo directory.
+        Each folder will be mounted at /net/rhea/{folder}.
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    # Enable NFS support
+    boot.supportedFilesystems = [ "nfs" ];
+
+    # Create NFS mounts for each folder
+    fileSystems = lib.listToAttrs (
+      map (folder: {
+        name = "/net/rhea/${folder}";
+        value = {
+          device = "rhea.sbr.pm:/${folder}"; # NFSv4: path relative to fsid=0 (/neo)
+          fsType = "nfs";
+          options = [
+            "nfsvers=4.2" # Use NFSv4.2 for best performance
+            "x-systemd.automount" # Lazy-mount on first access
+            "noauto" # Don't mount at boot
+            "x-systemd.idle-timeout=600" # Auto-unmount after 10 min idle
+            "soft" # Don't hang if server unavailable
+            "timeo=14" # Timeout after 1.4s (14 * 0.1s)
+            "retrans=2" # Retry twice before timing out
+            "_netdev" # Wait for network before mounting
+          ];
+        };
+      }) cfg.folders
+    );
+  };
+}
systems/kyushu/extra.nix
@@ -30,8 +30,6 @@
     ];
   };
 
-  boot.supportedFilesystems = [ "nfs" ];
-
   services = {
     getty = {
       autologinOnce = true;
systems/kyushu/hardware.nix
@@ -8,6 +8,7 @@
 
     ../common/hardware/acpid.nix
     ../common/hardware/bluetooth.nix
+    ../common/services/nfs-rhea-mounts.nix
   ];
 
   hardware = {
@@ -15,63 +16,14 @@
   };
 
   # NFS mounts from rhea
-  fileSystems."/net/rhea/audiobooks" = {
-    device = "rhea.sbr.pm:/audiobooks"; # NFSv4: path relative to fsid=0 (/neo)
-    fsType = "nfs";
-    options = [
-      "nfsvers=4.2" # Use NFSv4.2 for best performance
-      "x-systemd.automount" # Lazy-mount on first access
-      "noauto" # Don't mount at boot
-      "x-systemd.idle-timeout=600" # Auto-unmount after 10 min idle
-      "soft" # Don't hang if server unavailable
-      "timeo=14" # Timeout after 1.4s (14 * 0.1s)
-      "retrans=2" # Retry twice before timing out
-      "_netdev" # Wait for network before mounting
-    ];
-  };
-
-  fileSystems."/net/rhea/music" = {
-    device = "rhea.sbr.pm:/music"; # NFSv4: path relative to fsid=0 (/neo)
-    fsType = "nfs";
-    options = [
-      "nfsvers=4.2" # Use NFSv4.2 for best performance
-      "x-systemd.automount" # Lazy-mount on first access
-      "noauto" # Don't mount at boot
-      "x-systemd.idle-timeout=600" # Auto-unmount after 10 min idle
-      "soft" # Don't hang if server unavailable
-      "timeo=14" # Timeout after 1.4s (14 * 0.1s)
-      "retrans=2" # Retry twice before timing out
-      "_netdev" # Wait for network before mounting
-    ];
-  };
-
-  fileSystems."/net/rhea/pictures" = {
-    device = "rhea.sbr.pm:/pictures";
-    fsType = "nfs";
-    options = [
-      "nfsvers=4.2"
-      "x-systemd.automount"
-      "noauto"
-      "x-systemd.idle-timeout=600"
-      "soft"
-      "timeo=14"
-      "retrans=2"
-      "_netdev"
-    ];
-  };
-
-  fileSystems."/net/rhea/videos" = {
-    device = "rhea.sbr.pm:/videos";
-    fsType = "nfs";
-    options = [
-      "nfsvers=4.2"
-      "x-systemd.automount"
-      "noauto"
-      "x-systemd.idle-timeout=600"
-      "soft"
-      "timeo=14"
-      "retrans=2"
-      "_netdev"
+  services.nfs-rhea-mounts = {
+    enable = true;
+    folders = [
+      "audiobooks"
+      "downloads"
+      "music"
+      "pictures"
+      "videos"
     ];
   };
 
systems/kyushu/home.nix
@@ -21,6 +21,8 @@
     gmailctl
     gcalcli
 
+    calibre
+
     ntfy-sh
 
     monolith # TODO: move into =desktop= ?
systems/rhea/extra.nix
@@ -469,16 +469,6 @@
       group = "users";
       openFirewall = true;
     };
-    aria2 = {
-      # FIXME: make sure aria2 runs as user vincent
-      enable = true;
-      openPorts = true;
-      settings = {
-        max-concurrent-downloads = 20;
-        dir = "/neo/downloads";
-      };
-      rpcSecretFile = "${pkgs.writeText "aria" "aria2rpc\n"}"; # FIXME: use secrets for this somehow
-    };
     transmission = {
       enable = true;
       user = "vincent";
@@ -622,6 +612,7 @@
   environment.systemPackages = with pkgs; [
     lm_sensors
     gnumake
+    audible-converter
   ];
 
 }
systems/sakhalin/hardware.nix
@@ -4,6 +4,7 @@
 {
   imports = [
     ../common/hardware/acpid.nix
+    ../common/services/nfs-rhea-mounts.nix
   ];
   fileSystems."/" = {
     device = "/dev/disk/by-uuid/92ce650d-873e-41c1-a44e-71c2b9191b9d";
@@ -47,6 +48,18 @@
 
   swapDevices = [ { device = "/dev/disk/by-uuid/9eb067d1-b329-4fbb-ae27-38abfbe7c108"; } ];
 
+  # NFS mounts from rhea
+  services.nfs-rhea-mounts = {
+    enable = true;
+    folders = [
+      "audiobooks"
+      "downloads"
+      "music"
+      "pictures"
+      "videos"
+    ];
+  };
+
   networking = {
     firewall.enable = false; # we are in safe territory :D
     bridges.br1.interfaces = [ "enp0s31f6" ];