diff --git a/modules/nixos/server/services/ookflix/default.nix b/modules/nixos/server/services/ookflix/default.nix index f14c124..616bb63 100644 --- a/modules/nixos/server/services/ookflix/default.nix +++ b/modules/nixos/server/services/ookflix/default.nix @@ -1,11 +1,4 @@ { - lib, - config, - ... -}: let - inherit (lib) elem mkIf; - inherit (config.ooknet.server) services; -in { imports = [ ./jellyfin.nix ./plex.nix @@ -14,21 +7,9 @@ in { ./sonarr.nix ./prowlarr.nix ./gluetun.nix - ./transmission.nix + ./qbittorrent.nix ./shared.nix ./options.nix ]; - - config = mkIf (elem "ookflix" services) { - ooknet.server.ookflix = { - gpuAcceleration.enable = true; - services = { - jellyfin.enable = true; - plex.enable = true; - jellyseer.enable = true; - tautulli.enable = true; - }; - }; - }; } diff --git a/modules/nixos/server/services/ookflix/gluetun.nix b/modules/nixos/server/services/ookflix/gluetun.nix index 3f5fb84..cc56f80 100644 --- a/modules/nixos/server/services/ookflix/gluetun.nix +++ b/modules/nixos/server/services/ookflix/gluetun.nix @@ -6,27 +6,24 @@ ... }: let ookflixLib = import ./lib.nix {inherit self lib config;}; - inherit (ookflixLib) mkServiceUser; + inherit (ookflixLib) mkServiceUser mkServiceSecret; inherit (lib) mkIf; - inherit (ook.lib.container) mkContainerEnvironment mkContainerPort mkServiceSecret; - inherit (config.ooknet.server.ookflix.services) transmission gluetun; + inherit (ook.lib.container) mkContainerEnvironment mkContainerPort; + inherit (config.ooknet.server.ookflix.services) qbittorrent gluetun; in { config = mkIf gluetun.enable { users = mkServiceUser gluetun.user.name; - age.secrets.vpn_env = mkServiceSecret "vpn_env" "gluetun"; + age.secrets = mkServiceSecret "vpn_env" "gluetun"; virtualisation.oci-containers.containers = { # vpn container - gluetun = mkIf { + gluetun = mkIf gluetun.enable { image = "qmcgaw/gluetun:latest"; # should make this an option. environmentFiles = [config.age.secrets.vpn_env.path]; ports = [ - (mkContainerPort transmission.port) + (mkContainerPort qbittorrent.port) ]; - environment = mkContainerEnvironment gluetun.user.id gluetun.group.id { - VPN_SERVICE_PROVIDER = gluetun.provider; - VPN_TYPE = "wireguard"; - }; + environment = mkContainerEnvironment gluetun.user.id gluetun.group.id; extraOptions = [ # give network admin permissions "--cap-add=NET_ADMIN" diff --git a/modules/nixos/server/services/ookflix/jellyfin.nix b/modules/nixos/server/services/ookflix/jellyfin.nix index 0692b0e..6f30b4b 100644 --- a/modules/nixos/server/services/ookflix/jellyfin.nix +++ b/modules/nixos/server/services/ookflix/jellyfin.nix @@ -23,7 +23,7 @@ in { image = "lscr.io/linuxserver/jellyfin:latest"; autoStart = true; hostname = "jellyfin"; - ports = ["${jellyfin.port}:${jellyfin.port}"]; + ports = [(mkContainerPort jellyfin.port)]; volumes = [ "${volumes.media.root}:/data" "${jellyfin.stateDir}:/config" diff --git a/modules/nixos/server/services/ookflix/lib.nix b/modules/nixos/server/services/ookflix/lib.nix index 6cc065d..9b91566 100644 --- a/modules/nixos/server/services/ookflix/lib.nix +++ b/modules/nixos/server/services/ookflix/lib.nix @@ -9,6 +9,7 @@ inherit (lib.types) int path port str; inherit (config.ooknet) server; cfg = server.ookflix; + ookflixEnabled = elem "ookflix" server.services; mkSubdomainOption = name: description: example: mkOption { @@ -60,19 +61,25 @@ inherit description example; }; - mkVolumeOption = type: pathValue: + mkVolumeOption = rootPath: pathValue: mkOption { type = path; default = - if type == "state" + if rootPath == "state" then "${cfg.volumes.state.root}/${pathValue}" - else if type == "media" + else if rootPath == "data" + then "${cfg.volumes.data.root}/${pathValue}" + else if rootPath == "media" then "${cfg.volumes.media.root}/${pathValue}" - else if type == "downloads" - then "${cfg.volumes.downloads.root}/${pathValue}" - else if type == "root" + else if rootPath == "torrents" + then "${cfg.volumes.torrents.root}/${pathValue}" + else if rootPath == "usenet" + then "${cfg.volumes.usenet.root}/${pathValue}" + else if rootPath == "usenet/complete" + then "${cfg.volumes.usenet.complete.root}/${pathValue}" + else if rootPath == "root" then pathValue - else throw "Invalid VolumeOption type: ${type}. Must be one of 'state' 'media' 'downloads' 'root'"; + else throw "Invalid VolumeOption rootPath: ${rootPath}. Must be one of 'state' 'data' 'media' 'torrents' 'usenet' 'usenet/complete' 'root'"; }; mkServiceOptions = name: { @@ -81,7 +88,7 @@ uid, ... } @ args: { - enable = mkEnableOption "Enable ${name} container"; + enable = mkEnableOption "Enable ${name} container" // {default = ookflixEnabled;}; port = mkPortOption args.port "Port for ${name} container." 80; domain = mkSubdomainOption name "Domain for ${name} container." "${name}.mydomain.com"; stateDir = mkVolumeOption "state" name; @@ -93,7 +100,7 @@ uid, ... } @ args: { - enable = mkEnableOption "Enable ${name} container"; + enable = mkEnableOption "Enable ${name} container" // {default = ookflixEnabled;}; user = mkUserOption name args.uid; group = mkGroupOption name args.gid; }; @@ -118,7 +125,7 @@ }; mkServiceSecret = name: service: { ${name} = { - file = "${self}/secrets/container/${name}.age"; + file = "${self}/secrets/containers/${name}.age"; owner = cfg.services.${service}.user.name; group = cfg.services.${service}.group.name; }; diff --git a/modules/nixos/server/services/ookflix/options.nix b/modules/nixos/server/services/ookflix/options.nix index 8d0637b..3cddfdd 100644 --- a/modules/nixos/server/services/ookflix/options.nix +++ b/modules/nixos/server/services/ookflix/options.nix @@ -6,16 +6,19 @@ }: let ookflixLib = import ./lib.nix {inherit lib config self;}; - inherit (ookflixLib) mkVolumeOption mkGroupOption mkServiceOptions mkBasicServiceOptions; - inherit (lib) mkOption mkEnableOption; + inherit (ookflixLib) mkVolumeOption mkGroupOption mkServiceOptions mkBasicServiceOptions mkPortOption; + inherit (lib) mkOption mkEnableOption elem; + inherit (config.ooknet.server) services; inherit (lib.types) enum; - inherit (config.ooknet) server; - cfg = server.ookflix; in { options.ooknet.server.ookflix = { - enable = mkEnableOption "Enable ookflix a container based media server module"; + enable = + mkEnableOption "Enable ookflix a container based media server module" + // {default = elem "ookflix" services;}; gpuAcceleration = { - enable = mkEnableOption "Enable GPU acceleration for video streamers"; + enable = + mkEnableOption "Enable GPU acceleration for video streamers" + // {default = elem "ookflix" services;}; type = mkOption { type = enum ["nvidia" "intel" "amd"]; default = config.ooknet.hardware.gpu.type; @@ -28,15 +31,26 @@ in { volumes = { state.root = mkVolumeOption "root" "/var/lib/ookflix"; data.root = mkVolumeOption "root" "/jellyfin"; - downloads = { - root = mkVolumeOption "${cfg.content.root}/downloads"; - tv = mkVolumeOption "downloads" "tv"; - movies = mkVolumeOption "downloads" "movies"; - books = mkVolumeOption "downloads" "books"; + + torrents = { + root = mkVolumeOption "data" "torrents"; + tv = mkVolumeOption "torrents" "tv"; + movies = mkVolumeOption "torrents" "movies"; + books = mkVolumeOption "torrents" "books"; }; + usenet = { + root = mkVolumeOption "data" "usenet"; + incomplete = mkVolumeOption "usenet" "incomplete"; + complete = { + root = mkVolumeOption "usenet" "complete"; + tv = mkVolumeOption "usenet/complete" "tv"; + movies = mkVolumeOption "usenet/complete" "movies"; + books = mkVolumeOption "usenet/complete" "books"; + }; + }; media = { - root = mkVolumeOption "root" "${cfg.volumes.content.root}/media"; + root = mkVolumeOption "data" "media"; movies = mkVolumeOption "media" "movies"; tv = mkVolumeOption "media" "tv"; books = mkVolumeOption "media" "books"; @@ -74,11 +88,13 @@ in { uid = 982; gid = 987; }; - transmission = mkServiceOptions "transmission" { - port = 9091; - uid = 70; - gid = 70; - }; + qbittorrent = + mkServiceOptions "qbittorrent" { + port = 8080; + uid = 377; + gid = 377; + } + // {torrentPort = mkPortOption 58080 "Torrenting Port for qbittorrent" 58080;}; jellyseer = mkServiceOptions "jellyseer" { port = 5055; uid = 345; diff --git a/modules/nixos/server/services/ookflix/prowlarr.nix b/modules/nixos/server/services/ookflix/prowlarr.nix index ca8e5ed..ee5f333 100644 --- a/modules/nixos/server/services/ookflix/prowlarr.nix +++ b/modules/nixos/server/services/ookflix/prowlarr.nix @@ -22,7 +22,6 @@ in { hostname = "prowlarr"; ports = [(mkContainerPort prowlarr.port)]; volumes = ["${prowlarr.stateDir}:/config"]; - extraOptions = ["--network" "host"]; labels = mkContainerLabel { name = "prowlarr"; inherit (prowlarr) port domain; diff --git a/modules/nixos/server/services/ookflix/qbittorrent.nix b/modules/nixos/server/services/ookflix/qbittorrent.nix new file mode 100644 index 0000000..026a4de --- /dev/null +++ b/modules/nixos/server/services/ookflix/qbittorrent.nix @@ -0,0 +1,46 @@ +{ + config, + lib, + ook, + self, + ... +}: let + ookflixLib = import ./lib.nix {inherit lib config self;}; + inherit (ookflixLib) mkServiceUser mkServiceStateDir; + inherit (lib) mkIf; + inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment; + inherit (config.ooknet.server.ookflix) groups volumes; + inherit (config.ooknet.server.ookflix.services) qbittorrent; +in { + config = mkIf qbittorrent.enable { + users = mkServiceUser qbittorrent.user.name; + systemd.tmpfiles = mkServiceStateDir "qbittorrent" qbittorrent.stateDir; + virtualisation.oci-containers.containers = { + # Torrent client + qbittorrent = { + image = "ghcr.io/hotio/qbittorrent"; + dependsOn = ["gluetun"]; + volumes = [ + "${qbittorrent.stateDir}:/config" + "${volumes.torrents.root}:/data/torrents" + ]; + extraOptions = ["--network=container:gluetun"]; + labels = mkContainerLabel { + name = "qbittorrent"; + inherit (qbittorrent) port domain; + homepage = { + group = "downloads"; + description = "torrent client"; + }; + }; + environment = + mkContainerEnvironment qbittorrent.user.id groups.downloads.id + // { + UMASK = "002"; + WEBUI_PORTS = "${toString qbittorrent.port}/tcp,${toString qbittorrent.port}/udp"; + TORRENTING_PORT = "${toString qbittorrent.torrentPort}"; + }; + }; + }; + }; +} diff --git a/modules/nixos/server/services/ookflix/radarr.nix b/modules/nixos/server/services/ookflix/radarr.nix index d478631..b970381 100644 --- a/modules/nixos/server/services/ookflix/radarr.nix +++ b/modules/nixos/server/services/ookflix/radarr.nix @@ -25,7 +25,6 @@ in { "${radarr.stateDir}:/config" "${volumes.data.root}:/data" ]; - extraOptions = ["--network" "host"]; labels = mkContainerLabel { name = "radarr"; inherit (radarr) port domain; @@ -34,7 +33,11 @@ in { description = "media-server movies downloader"; }; }; - environment = mkContainerEnvironment radarr.user.id groups.media.id; + environment = + mkContainerEnvironment radarr.user.id groups.media.id + // { + UMASK = "002"; + }; }; }; }; diff --git a/modules/nixos/server/services/ookflix/shared.nix b/modules/nixos/server/services/ookflix/shared.nix index 87a5117..f8d61e1 100644 --- a/modules/nixos/server/services/ookflix/shared.nix +++ b/modules/nixos/server/services/ookflix/shared.nix @@ -7,59 +7,69 @@ inherit (config.ooknet.host) admin; inherit (config.ooknet.server) ookflix; inherit (config.ooknet.server.ookflix) volumes groups; - inherit (config.ooknet.server.ookflix.services) jellyfin plex sonarr radarr prowlarr transmission; - mediaDirPermissions = { + inherit (config.ooknet.server.ookflix.services) jellyfin plex sonarr radarr prowlarr qbittorrent; + dataDirPermissions = { mode = "0775"; user = admin.name; group = groups.media.name; }; - downloadDirPermissions = { - mode = "0770"; - user = admin.name; - group = groups.downloads.name; - }; ifTheyExist = users: builtins.filter (user: builtins.hasAttr user config.users.users) users; in { config = mkIf ookflix.enable { users.groups = { ${groups.media.name} = { - inherit (groups.media) name gid; + inherit (groups.media) name; + gid = groups.media.id; members = ifTheyExist [ + # need access to the media library jellyfin.user.name plex.user.name + + # need access to the media library and the torrent/usenet library sonarr.user.name radarr.user.name prowlarr.user.name - ]; - }; - ${groups.downloads.name} = { - inherit (groups.downloads) name gid; - members = ifTheyExist [ - sonarr.user.name - radarr.user.name - prowlarr.user.name - transmission.user.name + + # need access to the torrent library + qbittorrent.user.name ]; }; }; systemd.tmpfiles.settings = { - contentRoot = { - "${volumes.content.root}"."d" = { - mode = "0775"; - user = "root"; - group = "root"; - }; - }; - mediaDirectories = { - "${volumes.media.root}"."d" = mediaDirPermissions; - "${volumes.media.tv}"."d" = mediaDirPermissions; - "${volumes.media.movies}"."d" = mediaDirPermissions; - }; - downloadDirectories = { - "${volumes.downloads.root}"."d" = downloadDirPermissions; - "${volumes.downloads.complete}"."d" = downloadDirPermissions; - "${volumes.downloads.incomplete}"."d" = downloadDirPermissions; - "${volumes.downloads.watch}"."d" = downloadDirPermissions; + ookflixDataDirs = { + /* + set up the entire directory structure it should look something like this: + data + ├── torrents + │ ├── movies + │ ├── books + │ └── tv + ├── usenet + │ ├── incomplete + │ └── complete + │ ├── books + │ ├── movies + │ └── tv + └── media + ├── movies + ├── books + └── tv + */ + "${volumes.data.root}"."d" = dataDirPermissions; + "${volumes.torrents.root}"."d" = dataDirPermissions; + "${volumes.torrents.movies}"."d" = dataDirPermissions; + "${volumes.torrents.tv}"."d" = dataDirPermissions; + "${volumes.torrents.books}"."d" = dataDirPermissions; + "${volumes.usenet.root}"."d" = dataDirPermissions; + "${volumes.usenet.incomplete}"."d" = dataDirPermissions; + "${volumes.usenet.complete.root}"."d" = dataDirPermissions; + "${volumes.usenet.complete.movies}"."d" = dataDirPermissions; + "${volumes.usenet.complete.tv}"."d" = dataDirPermissions; + "${volumes.usenet.complete.books}"."d" = dataDirPermissions; + "${volumes.media.root}"."d" = dataDirPermissions; + "${volumes.media.movies}"."d" = dataDirPermissions; + "${volumes.media.tv}"."d" = dataDirPermissions; + "${volumes.media.books}"."d" = dataDirPermissions; }; }; }; diff --git a/modules/nixos/server/services/ookflix/transmission.nix b/modules/nixos/server/services/ookflix/transmission.nix deleted file mode 100644 index 0122cb3..0000000 --- a/modules/nixos/server/services/ookflix/transmission.nix +++ /dev/null @@ -1,43 +0,0 @@ -{ - config, - lib, - ook, - self, - ... -}: let - ookflixLib = import ./lib.nix {inherit lib config self;}; - inherit (ookflixLib) mkServiceUser mkServiceStateDir; - inherit (lib) mkIf; - inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainerPort; - inherit (config.ooknet.server.ookflix) groups volumes; - inherit (config.ooknet.server.ookflix.services) transmission gluetun; -in { - config = mkIf transmission.enable { - users = mkServiceUser transmission.user.name; - systemd.tmpfiles = mkServiceStateDir "transmission" transmission.stateDir; - virtualisation.oci-containers.containers = { - # Torrent client - transmission = { - image = "lscr.io/linuxserver/transmission:latest"; - environmentFiles = [config.age.secrets.transmission_env.path]; - environment = mkContainerEnvironment transmission.user.id groups.downloads.id; - dependsOn = ["gluetun"]; - networkMode = "service:gluetun"; # Use VPN container's network - volumes = [ - "${transmission.stateDir}:/config" - "${volumes.downloads.root}:/downloads" - "${volumes.downloads.watch}:/watch" - ]; - extraOptions = ["--network=container:gluetun"]; - labels = mkContainerLabel { - name = "transmission"; - inherit (transmission) port domain; - homepage = { - group = "downloads"; - description = "torrent client"; - }; - }; - }; - }; - }; -}