From c21b7a632cbc954c7a550bc5a99bbb210edc9666 Mon Sep 17 00:00:00 2001 From: alexion Date: Sat, 12 Sep 2026 18:48:05 -0400 Subject: [PATCH] feat(nixos): add navidrome guest module --- configs/nixos/guests/navidrome.nix | 109 +++++++++++++++++++ configs/nixos/modules/services/navidrome.nix | 92 ++++++++++++++++ configs/nixos/registry/stable-uid.nix | 2 +- 3 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 configs/nixos/guests/navidrome.nix create mode 100644 configs/nixos/modules/services/navidrome.nix diff --git a/configs/nixos/guests/navidrome.nix b/configs/nixos/guests/navidrome.nix new file mode 100644 index 0000000..61cace4 --- /dev/null +++ b/configs/nixos/guests/navidrome.nix @@ -0,0 +1,109 @@ +{ + config, + lib, + ... +}: +let + cfg = config.guests.navidrome; +in +{ + options.guests.navidrome = { + dataPath = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "/srv/navidrome"; + description = "Host path bind-mounted as Navidrome's state directory."; + }; + + musicPath = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "/srv/music"; + description = "Host path bind-mounted as Navidrome's music directory."; + }; + + dataDir = lib.mkOption { + type = lib.types.str; + default = "/var/lib/navidrome"; + description = "Guest path where Navidrome stores state."; + }; + + musicDir = lib.mkOption { + type = lib.types.str; + default = "/music"; + description = "Guest path where Navidrome reads the music library."; + }; + + port = lib.mkOption { + type = lib.types.port; + default = 4533; + description = "Port Navidrome listens on."; + }; + + enableSharing = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enables Navidrome sharing support."; + }; + + settings = lib.mkOption { + type = lib.types.attrs; + default = { }; + description = "Additional non-secret Navidrome settings."; + }; + + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = "Guest path to a file containing secret Navidrome environment variables."; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.dataPath != null; + message = "guests.navidrome.dataPath must point at the host directory that stores Navidrome state."; + } + { + assertion = cfg.musicPath != null; + message = "guests.navidrome.musicPath must point at the host directory that stores the music library."; + } + ]; + + guests.navidrome = { + interior.modules.services.navidrome = { + enable = true; + inherit (cfg) + dataDir + musicDir + port + enableSharing + settings + environmentFile + ; + }; + + mounts = { + ${cfg.dataDir} = { + directory = cfg.dataPath; + owner = config.registry."stable-uid".${config.networking.hostName}.navidrome; + group = "storage"; + mode = "0770"; + }; + ${cfg.musicDir} = { + directory = cfg.musicPath; + owner = "root"; + group = "storage"; + mode = "2770"; + }; + }; + + limits = { + memory = lib.mkDefault "2G"; + cpu = lib.mkDefault "200%"; + tasksMax = lib.mkDefault 512; + }; + }; + }; +} diff --git a/configs/nixos/modules/services/navidrome.nix b/configs/nixos/modules/services/navidrome.nix new file mode 100644 index 0000000..975c87b --- /dev/null +++ b/configs/nixos/modules/services/navidrome.nix @@ -0,0 +1,92 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.modules.services.navidrome; +in +{ + options.modules.services.navidrome = { + enable = lib.mkEnableOption "Navidrome"; + + package = lib.mkPackageOption pkgs "navidrome" { }; + + port = lib.mkOption { + type = lib.types.port; + default = 4533; + description = "Port Navidrome listens on."; + }; + + dataDir = lib.mkOption { + type = lib.types.str; + default = "/var/lib/navidrome"; + description = "Directory where Navidrome stores state."; + }; + + musicDir = lib.mkOption { + type = lib.types.str; + default = "/music"; + description = "Directory where Navidrome reads the music library."; + }; + + user = lib.mkOption { + type = lib.types.str; + default = "navidrome"; + description = "User account that runs Navidrome."; + }; + + group = lib.mkOption { + type = lib.types.str; + default = "storage"; + description = "Group account that owns Navidrome state and media access."; + }; + + enableSharing = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enables Navidrome sharing support."; + }; + + settings = lib.mkOption { + type = lib.types.attrs; + default = { }; + description = "Additional non-secret Navidrome settings."; + }; + + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = "File containing secret Navidrome environment variables."; + }; + }; + + config = lib.mkMerge [ + { + registry."stable-uid".${config.networking.hostName}.navidrome = 20004; + } + + (lib.mkIf cfg.enable { + users.users.${cfg.user} = { + isSystemUser = true; + uid = config.registry."stable-uid".${config.networking.hostName}.navidrome; + group = cfg.group; + home = cfg.dataDir; + }; + + services.navidrome = { + enable = true; + inherit (cfg) package user group environmentFile; + openFirewall = true; + settings = cfg.settings // { + Address = "0.0.0.0"; + Port = cfg.port; + DataFolder = cfg.dataDir; + MusicFolder = cfg.musicDir; + EnableSharing = cfg.enableSharing; + }; + }; + }) + ]; +} diff --git a/configs/nixos/registry/stable-uid.nix b/configs/nixos/registry/stable-uid.nix index 584c84a..7d2b18b 100644 --- a/configs/nixos/registry/stable-uid.nix +++ b/configs/nixos/registry/stable-uid.nix @@ -17,7 +17,7 @@ let in { - # Next stable UID: 20003 + # Next stable UID: 20005 replicate = true; type = lib.types.ints.positive;