OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      7590d9af07e8
DATE      2024-11-23
SUBJECT   server: initial media server config
FILES     13 CHANGED
HASH      7590d9af07e8
DATE      2024-11-23
SUBJECT   server: initial media server config
FILES     13 CHANGED
 

diff --git a/modules/nixos/server/options.nix b/modules/nixos/server/options.nix
index 2b437fd..4de3252 100644
--- a/modules/nixos/server/options.nix
+++ b/modules/nixos/server/options.nix
@@ -14,7 +14,7 @@ in {
       description = "The server profile the host will use as a base";
     };
     services = mkOption {
-      type = listOf (enum ["website" "forgejo"]);
+      type = listOf (enum ["media-server" "website" "forgejo"]);
       default = [];
       description = "List of services the server will host";
     };

diff --git a/modules/nixos/server/options.ni
x b/modules/nixos/server/options.nix
index 2b437fd..4de3252 100644
--- a/modules/nixos/server/options.nix
+++ b/modules/nixos/server/options.nix
@@ -14,7 +14,7 @@ in {
       description = "The server profile the
 host will use as a base";
     };
     services = mkOption {
-      type = listOf (enum ["website" "forge
jo"]);
+      type = listOf (enum ["media-server" "
website" "forgejo"]);
       default = [];
       description = "List of services the s
erver will host";
     };
 

diff --git a/modules/nixos/server/services/default.nix b/modules/nixos/server/serv
ices/default.nix
index 6d19766..7685461 100644
--- a/modules/nixos/server/services/default.nix
+++ b/modules/nixos/server/services/default.nix
@@ -2,5 +2,6 @@
   imports = [
     ./website
     ./forgejo
+    ./media-server
   ];
 }

diff --git a/modules/nixos/server/services/d
efault.nix b/modules/nixos/server/services/d
efault.nix
index 6d19766..7685461 100644
--- a/modules/nixos/server/services/default.
nix
+++ b/modules/nixos/server/services/default.
nix
@@ -2,5 +2,6 @@
   imports = [
     ./website
     ./forgejo
+    ./media-server
   ];
 }
 

diff --git a/modules/nixos/server/services/media-server/default.nix b/modules/nixo
s/server/services/media-server/default.nix
new file mode 100644
index 0000000..a5bbd81
--- /dev/null
+++ b/modules/nixos/server/services/media-server/default.nix
@@ -0,0 +1,30 @@
+{
+  lib,
+  config,
+  ...
+}: let
+  inherit (lib) mkIf elem;
+  inherit (config.ooknet.server) services;
+in {
+  imports = [
+    ./plex.nix
+    ./users.nix
+    ./options.nix
+    ./jellyfin.nix
+    ./transmission.nix
+    ./file-permissions.nix
+  ];
+
+  # short cut for enabling all media-server modules
+  config = mkIf (elem "media-server" services) {
+    ooknet.server.media-server = {
+      enable = true;
+      jellyfin.enable = true;
+      plex.enable = true;
+      transmission.enable = true;
+      radarr.enable = true;
+      sonarr.enable = true;
+      prowlarr.enable = true;
+    };
+  };
+}

diff --git a/modules/nixos/server/services/m
edia-server/default.nix b/modules/nixos/serv
er/services/media-server/default.nix
new file mode 100644
index 0000000..a5bbd81
--- /dev/null
+++ b/modules/nixos/server/services/media-se
rver/default.nix
@@ -0,0 +1,30 @@
+{
+  lib,
+  config,
+  ...
+}: let
+  inherit (lib) mkIf elem;
+  inherit (config.ooknet.server) services;
+in {
+  imports = [
+    ./plex.nix
+    ./users.nix
+    ./options.nix
+    ./jellyfin.nix
+    ./transmission.nix
+    ./file-permissions.nix
+  ];
+
+  # short cut for enabling all media-server
 modules
+  config = mkIf (elem "media-server" servic
es) {
+    ooknet.server.media-server = {
+      enable = true;
+      jellyfin.enable = true;
+      plex.enable = true;
+      transmission.enable = true;
+      radarr.enable = true;
+      sonarr.enable = true;
+      prowlarr.enable = true;
+    };
+  };
+}
 

diff --git a/modules/nixos/server/services/media-server/file-permissions.nix b/mod
ules/nixos/server/services/media-server/file-permissions.nix
new file mode 100644
index 0000000..b791728
--- /dev/null
+++ b/modules/nixos/server/services/media-server/file-permissions.nix
@@ -0,0 +1,42 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (config.ooknet.server) media-server;
+  inherit (config.ooknet.server.media-server) storage groups users;
+
+  contentPermissions = {
+    group = groups.media;
+    user = "root";
+    mode = "0775";
+  };
+
+  downloadPermissions = {
+    group = groups.media;
+    user = users.downloader;
+    mode = "0775";
+  };
+in {
+  config = mkIf media-server.enable {
+    systemd.tmpfiles.settings = {
+      content-dirs = {
+        "${storage.content.root}"."d" = contentPermissions;
+        "${storage.content.movies}"."d" = contentPermissions;
+        "${storage.content.tv}"."d" = contentPermissions;
+        "${storage.content.music}"."d" = contentPermissions;
+        "${storage.content.books}"."d" = contentPermissions;
+      };
+      download-dirs = {
+        "${storage.downloads.root}"."d" = downloadPermissions;
+        "${storage.downloads.incomplete}"."d" = downloadPermissions;
+        "${storage.downloads.watch}"."d" = downloadPermissions;
+        "${storage.downloads.manual}"."d" = downloadPermissions;
+        "${storage.downloads.radarr}"."d" = downloadPermissions;
+        "${storage.downloads.sonarr}"."d" = downloadPermissions;
+        "${storage.downloads.readarr}"."d" = downloadPermissions;
+      };
+    };
+  };
+}

diff --git a/modules/nixos/server/services/m
edia-server/file-permissions.nix b/modules/n
ixos/server/services/media-server/file-permi
ssions.nix
new file mode 100644
index 0000000..b791728
--- /dev/null
+++ b/modules/nixos/server/services/media-se
rver/file-permissions.nix
@@ -0,0 +1,42 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (config.ooknet.server) media-serv
er;
+  inherit (config.ooknet.server.media-serve
r) storage groups users;
+
+  contentPermissions = {
+    group = groups.media;
+    user = "root";
+    mode = "0775";
+  };
+
+  downloadPermissions = {
+    group = groups.media;
+    user = users.downloader;
+    mode = "0775";
+  };
+in {
+  config = mkIf media-server.enable {
+    systemd.tmpfiles.settings = {
+      content-dirs = {
+        "${storage.content.root}"."d" = con
tentPermissions;
+        "${storage.content.movies}"."d" = c
ontentPermissions;
+        "${storage.content.tv}"."d" = conte
ntPermissions;
+        "${storage.content.music}"."d" = co
ntentPermissions;
+        "${storage.content.books}"."d" = co
ntentPermissions;
+      };
+      download-dirs = {
+        "${storage.downloads.root}"."d" = d
ownloadPermissions;
+        "${storage.downloads.incomplete}"."
d" = downloadPermissions;
+        "${storage.downloads.watch}"."d" = 
downloadPermissions;
+        "${storage.downloads.manual}"."d" =
 downloadPermissions;
+        "${storage.downloads.radarr}"."d" =
 downloadPermissions;
+        "${storage.downloads.sonarr}"."d" =
 downloadPermissions;
+        "${storage.downloads.readarr}"."d" 
= downloadPermissions;
+      };
+    };
+  };
+}
 

diff --git a/modules/nixos/server/services/media-server/jellyfin.nix b/modules/nix
os/server/services/media-server/jellyfin.nix
new file mode 100644
index 0000000..8caf355
--- /dev/null
+++ b/modules/nixos/server/services/media-server/jellyfin.nix
@@ -0,0 +1,20 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (config.ooknet.server) media-server;
+  inherit (config.ooknet.server.media-server) storage groups users domain proxy;
+in {
+  config = mkIf media-server.jellyfin.enable {
+    services.jellyfin = {
+      enable = true;
+      user = users.streamer;
+      group = groups.media;
+      dataDir = storage.state.jellyfin;
+    };
+    ooknet.server.webserver.caddy.enable = true;
+    services.caddy.virtualHosts."${domain.jellyfin}".extraConfig = proxy.jellyfin
;
+  };
+}

diff --git a/modules/nixos/server/services/m
edia-server/jellyfin.nix b/modules/nixos/ser
ver/services/media-server/jellyfin.nix
new file mode 100644
index 0000000..8caf355
--- /dev/null
+++ b/modules/nixos/server/services/media-se
rver/jellyfin.nix
@@ -0,0 +1,20 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (config.ooknet.server) media-serv
er;
+  inherit (config.ooknet.server.media-serve
r) storage groups users domain proxy;
+in {
+  config = mkIf media-server.jellyfin.enabl
e {
+    services.jellyfin = {
+      enable = true;
+      user = users.streamer;
+      group = groups.media;
+      dataDir = storage.state.jellyfin;
+    };
+    ooknet.server.webserver.caddy.enable = 
true;
+    services.caddy.virtualHosts."${domain.j
ellyfin}".extraConfig = proxy.jellyfin;
+  };
+}
 

diff --git a/modules/nixos/server/services/media-server/options.nix b/modules/nixo
s/server/services/media-server/options.nix
new file mode 100644
index 0000000..a9c89b3
--- /dev/null
+++ b/modules/nixos/server/services/media-server/options.nix
@@ -0,0 +1,242 @@
+{
+  lib,
+  config,
+  ...
+}: let
+  inherit (lib) mkOption mkEnableOption;
+  inherit (lib.types) path port str lines;
+  inherit (config.ooknet) server;
+  cfg = server.media-server;
+
+  mkSubdomain = name:
+    mkOption {
+      type = str;
+      default = "${name}.${server.domain}";
+    };
+
+  mkProxy = port: ''
+    encode zstd gzip
+    reverse_proxy localhost:${toString port} {
+      header_up X-Real-IP {remote_host}
+      header_up X-Forwarded-For {remote_host}
+      header_up X-Forwarded-Proto {scheme}
+    }
+  '';
+in {
+  options.ooknet.server.media-server = {
+    enable = mkEnableOption "Enable media server functionality";
+
+    jellyfin.enable = mkEnableOption "Enable the Jellyfin module";
+    plex.enable = mkEnableOption "Enable Plex module";
+    transmission.enable = mkEnableOption "Enable Transmission module";
+    radarr.enable = mkEnableOption "Enable Radarr module";
+    sonarr.enable = mkEnableOption "Enable Sonarr module";
+    prowlarr.enable = mkEnableOption "Enable Sonarr module";
+
+    storage = {
+      mediaRoot = mkOption {
+        type = path;
+        default = "/media";
+        description = "Root directory for all media-related storage";
+      };
+
+      content = {
+        root = mkOption {
+          type = path;
+          default = "${cfg.storage.mediaRoot}/content";
+          description = "Root directory for media content";
+        };
+        movies = mkOption {
+          type = path;
+          default = "${cfg.storage.content.root}/movies";
+        };
+        tv = mkOption {
+          type = path;
+          default = "${cfg.storage.content.root}/tv";
+        };
+        music = mkOption {
+          type = path;
+          default = "${cfg.storage.content.root}/music";
+        };
+        books = mkOption {
+          type = path;
+          default = "${cfg.storage.content.root}/books";
+        };
+      };
+
+      downloads = {
+        root = mkOption {
+          type = path;
+          default = "${cfg.storage.mediaRoot}/downloads";
+        };
+        incomplete = mkOption {
+          type = path;
+          default = "${cfg.storage.downloads.root}/.incomplete";
+        };
+        watch = mkOption {
+          type = path;
+          default = "${cfg.storage.downloads.root}/.watch";
+        };
+        manual = mkOption {
+          type = path;
+          default = "${cfg.storage.downloads.root}/manual";
+        };
+        radarr = mkOption {
+          type = path;
+          default = "${cfg.storage.downloads.root}/radarr";
+        };
+        sonarr = mkOption {
+          type = path;
+          default = "${cfg.storage.downloads.root}/sonarr";
+        };
+        readarr = mkOption {
+          type = path;
+          default = "${cfg.storage.downloads.root}/readarr";
+        };
+      };
+
+      state = {
+        root = mkOption {
+          type = path;
+          default = "/var/lib";
+          description = "Root directory for service state";
+        };
+        jellyfin = mkOption {
+          type = path;
+          default = "${cfg.storage.state.root}/jellyfin";
+        };
+        plex = mkOption {
+          type = path;
+          default = "${cfg.storage.state.root}/plex";
+        };
+        sonarr = mkOption {
+          type = path;
+          default = "${cfg.storage.state.root}/sonarr";
+        };
+        radarr = mkOption {
+          type = path;
+          default = "${cfg.storage.state.root}/radarr";
+        };
+        transmission = mkOption {
+          type = path;
+          default = "${cfg.storage.state.root}/transmission";
+        };
+      };
+    };
+
+    groups = {
+      media = mkOption {
+        type = str;
+        default = "media";
+      };
+      prowlarr = mkOption {
+        type = str;
+        default = "prowlarr";
+      };
+      radarr = mkOption {
+        type = str;
+        default = "radarr";
+      };
+    };
+
+    users = {
+      jellyfin = mkOption {
+        type = str;
+        default = "jellyfin";
+      };
+      plex = mkOption {
+        type = str;
+        default = "plex";
+      };
+      sonarr = mkOption {
+        type = str;
+        default = "sonarr";
+      };
+      transmission = mkOption {
+        type = str;
+        default = "transmission";
+      };
+      prowlarr = mkOption {
+        type = str;
+        default = "prowlarr";
+      };
+      downloader = mkOption {
+        type = str;
+        default = "downloader";
+      };
+      streamer = mkOption {
+        type = str;
+        default = "streamer";
+      };
+    };
+
+    ports = {
+      jellyfin = mkOption {
+        type = port;
+        default = 8096;
+      };
+      plex = mkOption {
+        type = port;
+        default = 32400;
+      };
+      transmission = {
+        web = mkOption {
+          type = port;
+          default = 9091;
+        };
+        peer = mkOption {
+          type = port;
+          default = 50000;
+        };
+      };
+      sonarr = mkOption {
+        type = port;
+        default = 8989;
+      };
+      radarr = mkOption {
+        type = port;
+        default = 7878;
+      };
+      prowlarr = mkOption {
+        type = port;
+        default = 9696;
+      };
+    };
+
+    domain = {
+      jellyfin = mkSubdomain "jellyfin";
+      plex = mkSubdomain "plex";
+      transmission = mkSubdomain "transmission";
+      sonarr = mkSubdomain "sonarr";
+      radarr = mkSubdomain "radarr";
+      prowlarr = mkSubdomain "prowlarr";
+    };
+
+    proxy = {
+      jellyfin = mkOption {
+        type = lines;
+        default = mkProxy cfg.ports.jellyfin;
+      };
+      plex = mkOption {
+        type = lines;
+        default = mkProxy cfg.ports.plex;
+      };
+      sonarr = mkOption {
+        type = lines;
+        default = mkProxy cfg.ports.sonarr;
+      };
+      radarr = mkOption {
+        type = lines;
+        default = mkProxy cfg.ports.radarr;
+      };
+      prowlarr = mkOption {
+        type = lines;
+        default = mkProxy cfg.ports.prowlarr;
+      };
+      transmission = mkOption {
+        type = lines;
+        default = mkProxy cfg.ports.transmission.web;
+      };
+    };
+  };
+}

diff --git a/modules/nixos/server/services/m
edia-server/options.nix b/modules/nixos/serv
er/services/media-server/options.nix
new file mode 100644
index 0000000..a9c89b3
--- /dev/null
+++ b/modules/nixos/server/services/media-se
rver/options.nix
@@ -0,0 +1,242 @@
+{
+  lib,
+  config,
+  ...
+}: let
+  inherit (lib) mkOption mkEnableOption;
+  inherit (lib.types) path port str lines;
+  inherit (config.ooknet) server;
+  cfg = server.media-server;
+
+  mkSubdomain = name:
+    mkOption {
+      type = str;
+      default = "${name}.${server.domain}";
+    };
+
+  mkProxy = port: ''
+    encode zstd gzip
+    reverse_proxy localhost:${toString port
} {
+      header_up X-Real-IP {remote_host}
+      header_up X-Forwarded-For {remote_hos
t}
+      header_up X-Forwarded-Proto {scheme}
+    }
+  '';
+in {
+  options.ooknet.server.media-server = {
+    enable = mkEnableOption "Enable media s
erver functionality";
+
+    jellyfin.enable = mkEnableOption "Enabl
e the Jellyfin module";
+    plex.enable = mkEnableOption "Enable Pl
ex module";
+    transmission.enable = mkEnableOption "E
nable Transmission module";
+    radarr.enable = mkEnableOption "Enable 
Radarr module";
+    sonarr.enable = mkEnableOption "Enable 
Sonarr module";
+    prowlarr.enable = mkEnableOption "Enabl
e Sonarr module";
+
+    storage = {
+      mediaRoot = mkOption {
+        type = path;
+        default = "/media";
+        description = "Root directory for a
ll media-related storage";
+      };
+
+      content = {
+        root = mkOption {
+          type = path;
+          default = "${cfg.storage.mediaRoo
t}/content";
+          description = "Root directory for
 media content";
+        };
+        movies = mkOption {
+          type = path;
+          default = "${cfg.storage.content.
root}/movies";
+        };
+        tv = mkOption {
+          type = path;
+          default = "${cfg.storage.content.
root}/tv";
+        };
+        music = mkOption {
+          type = path;
+          default = "${cfg.storage.content.
root}/music";
+        };
+        books = mkOption {
+          type = path;
+          default = "${cfg.storage.content.
root}/books";
+        };
+      };
+
+      downloads = {
+        root = mkOption {
+          type = path;
+          default = "${cfg.storage.mediaRoo
t}/downloads";
+        };
+        incomplete = mkOption {
+          type = path;
+          default = "${cfg.storage.download
s.root}/.incomplete";
+        };
+        watch = mkOption {
+          type = path;
+          default = "${cfg.storage.download
s.root}/.watch";
+        };
+        manual = mkOption {
+          type = path;
+          default = "${cfg.storage.download
s.root}/manual";
+        };
+        radarr = mkOption {
+          type = path;
+          default = "${cfg.storage.download
s.root}/radarr";
+        };
+        sonarr = mkOption {
+          type = path;
+          default = "${cfg.storage.download
s.root}/sonarr";
+        };
+        readarr = mkOption {
+          type = path;
+          default = "${cfg.storage.download
s.root}/readarr";
+        };
+      };
+
+      state = {
+        root = mkOption {
+          type = path;
+          default = "/var/lib";
+          description = "Root directory for
 service state";
+        };
+        jellyfin = mkOption {
+          type = path;
+          default = "${cfg.storage.state.ro
ot}/jellyfin";
+        };
+        plex = mkOption {
+          type = path;
+          default = "${cfg.storage.state.ro
ot}/plex";
+        };
+        sonarr = mkOption {
+          type = path;
+          default = "${cfg.storage.state.ro
ot}/sonarr";
+        };
+        radarr = mkOption {
+          type = path;
+          default = "${cfg.storage.state.ro
ot}/radarr";
+        };
+        transmission = mkOption {
+          type = path;
+          default = "${cfg.storage.state.ro
ot}/transmission";
+        };
+      };
+    };
+
+    groups = {
+      media = mkOption {
+        type = str;
+        default = "media";
+      };
+      prowlarr = mkOption {
+        type = str;
+        default = "prowlarr";
+      };
+      radarr = mkOption {
+        type = str;
+        default = "radarr";
+      };
+    };
+
+    users = {
+      jellyfin = mkOption {
+        type = str;
+        default = "jellyfin";
+      };
+      plex = mkOption {
+        type = str;
+        default = "plex";
+      };
+      sonarr = mkOption {
+        type = str;
+        default = "sonarr";
+      };
+      transmission = mkOption {
+        type = str;
+        default = "transmission";
+      };
+      prowlarr = mkOption {
+        type = str;
+        default = "prowlarr";
+      };
+      downloader = mkOption {
+        type = str;
+        default = "downloader";
+      };
+      streamer = mkOption {
+        type = str;
+        default = "streamer";
+      };
+    };
+
+    ports = {
+      jellyfin = mkOption {
+        type = port;
+        default = 8096;
+      };
+      plex = mkOption {
+        type = port;
+        default = 32400;
+      };
+      transmission = {
+        web = mkOption {
+          type = port;
+          default = 9091;
+        };
+        peer = mkOption {
+          type = port;
+          default = 50000;
+        };
+      };
+      sonarr = mkOption {
+        type = port;
+        default = 8989;
+      };
+      radarr = mkOption {
+        type = port;
+        default = 7878;
+      };
+      prowlarr = mkOption {
+        type = port;
+        default = 9696;
+      };
+    };
+
+    domain = {
+      jellyfin = mkSubdomain "jellyfin";
+      plex = mkSubdomain "plex";
+      transmission = mkSubdomain "transmiss
ion";
+      sonarr = mkSubdomain "sonarr";
+      radarr = mkSubdomain "radarr";
+      prowlarr = mkSubdomain "prowlarr";
+    };
+
+    proxy = {
+      jellyfin = mkOption {
+        type = lines;
+        default = mkProxy cfg.ports.jellyfi
n;
+      };
+      plex = mkOption {
+        type = lines;
+        default = mkProxy cfg.ports.plex;
+      };
+      sonarr = mkOption {
+        type = lines;
+        default = mkProxy cfg.ports.sonarr;
+      };
+      radarr = mkOption {
+        type = lines;
+        default = mkProxy cfg.ports.radarr;
+      };
+      prowlarr = mkOption {
+        type = lines;
+        default = mkProxy cfg.ports.prowlar
r;
+      };
+      transmission = mkOption {
+        type = lines;
+        default = mkProxy cfg.ports.transmi
ssion.web;
+      };
+    };
+  };
+}
 

diff --git a/modules/nixos/server/services/media-server/plex.nix b/modules/nixos/s
erver/services/media-server/plex.nix
new file mode 100644
index 0000000..5c4bfb6
--- /dev/null
+++ b/modules/nixos/server/services/media-server/plex.nix
@@ -0,0 +1,20 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (config.ooknet.server) media-server;
+  inherit (config.ooknet.server.media-server) groups users storage domain proxy;
+in {
+  config = mkIf media-server.plex.enable {
+    services.plex = {
+      enable = true;
+      user = users.streamer;
+      group = groups.media;
+      dataDir = storage.state.plex;
+    };
+    ooknet.server.webserver.caddy.enable = true;
+    services.caddy.virtualHosts."${domain.plex}".extraConfig = proxy.plex;
+  };
+}

diff --git a/modules/nixos/server/services/m
edia-server/plex.nix b/modules/nixos/server/
services/media-server/plex.nix
new file mode 100644
index 0000000..5c4bfb6
--- /dev/null
+++ b/modules/nixos/server/services/media-se
rver/plex.nix
@@ -0,0 +1,20 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (config.ooknet.server) media-serv
er;
+  inherit (config.ooknet.server.media-serve
r) groups users storage domain proxy;
+in {
+  config = mkIf media-server.plex.enable {
+    services.plex = {
+      enable = true;
+      user = users.streamer;
+      group = groups.media;
+      dataDir = storage.state.plex;
+    };
+    ooknet.server.webserver.caddy.enable = 
true;
+    services.caddy.virtualHosts."${domain.p
lex}".extraConfig = proxy.plex;
+  };
+}
 

diff --git a/modules/nixos/server/services/media-server/prowlarr.nix b/modules/nix
os/server/services/media-server/prowlarr.nix
new file mode 100644
index 0000000..b4efd5c
--- /dev/null
+++ b/modules/nixos/server/services/media-server/prowlarr.nix
@@ -0,0 +1,48 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}: let
+  inherit (lib) mkIf getExe;
+  inherit (config.ooknet.server) media-server;
+  inherit (config.ooknet.server.media-server) storage users groups domain proxy;
+in {
+  config = mkIf media-server.prowlarr.enable {
+    # we dont use the nixpkgs prowlarr service module because it lacks the option
 to
+    # declare dataDir, user and group.
+
+    # setup user
+    users.users.prowlarr = {
+      group = groups.prowlarr;
+      home = storage.state.prowlarr;
+    };
+    users.groups.prowlarr = {};
+
+    # basic systemd service
+    systemd = {
+      services.prowlarr = {
+        description = "Prowlarr";
+        after = ["network.target"];
+        wantedBy = ["multi-user.target"];
+
+        serviceConfig = {
+          Type = "simple";
+          User = users.prowlarr;
+          group = groups.prowlarr;
+          ExecStart = "${getExe pkgs.prowlarr} -nobrowser -data=${storage.state.p
rowlarr}";
+          Restart = "on-failure";
+        };
+      };
+      tmpfiles.settings.prowlarrDirs = {
+        "${storage.state.prowlarr}"."d" = {
+          mode = "700";
+          user = users.prowlarr;
+          group = groups.prowlarr;
+        };
+      };
+    };
+    ooknet.server.webserver.caddy.enable = true;
+    services.caddy.virtualHosts."${domain.prowlarr}".extraConfig = proxy.prowlarr
;
+  };
+}

diff --git a/modules/nixos/server/services/m
edia-server/prowlarr.nix b/modules/nixos/ser
ver/services/media-server/prowlarr.nix
new file mode 100644
index 0000000..b4efd5c
--- /dev/null
+++ b/modules/nixos/server/services/media-se
rver/prowlarr.nix
@@ -0,0 +1,48 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}: let
+  inherit (lib) mkIf getExe;
+  inherit (config.ooknet.server) media-serv
er;
+  inherit (config.ooknet.server.media-serve
r) storage users groups domain proxy;
+in {
+  config = mkIf media-server.prowlarr.enabl
e {
+    # we dont use the nixpkgs prowlarr serv
ice module because it lacks the option to
+    # declare dataDir, user and group.
+
+    # setup user
+    users.users.prowlarr = {
+      group = groups.prowlarr;
+      home = storage.state.prowlarr;
+    };
+    users.groups.prowlarr = {};
+
+    # basic systemd service
+    systemd = {
+      services.prowlarr = {
+        description = "Prowlarr";
+        after = ["network.target"];
+        wantedBy = ["multi-user.target"];
+
+        serviceConfig = {
+          Type = "simple";
+          User = users.prowlarr;
+          group = groups.prowlarr;
+          ExecStart = "${getExe pkgs.prowla
rr} -nobrowser -data=${storage.state.prowlar
r}";
+          Restart = "on-failure";
+        };
+      };
+      tmpfiles.settings.prowlarrDirs = {
+        "${storage.state.prowlarr}"."d" = {
+          mode = "700";
+          user = users.prowlarr;
+          group = groups.prowlarr;
+        };
+      };
+    };
+    ooknet.server.webserver.caddy.enable = 
true;
+    services.caddy.virtualHosts."${domain.p
rowlarr}".extraConfig = proxy.prowlarr;
+  };
+}
 

diff --git a/modules/nixos/server/services/media-server/radarr.nix b/modules/nixos
/server/services/media-server/radarr.nix
new file mode 100644
index 0000000..beb5784
--- /dev/null
+++ b/modules/nixos/server/services/media-server/radarr.nix
@@ -0,0 +1,20 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (config.ooknet.server) media-server;
+  inherit (config.ooknet.server.media-server) storage users groups domain proxy;
+in {
+  config = mkIf media-server.radarr.enable {
+    services.radarr = {
+      enable = true;
+      user = users.radarr;
+      group = groups.radarr;
+      dataDir = storage.state.radaar;
+    };
+    ooknet.server.webserver.caddy.enable = true;
+    services.caddy.virtualHosts."${domain.radarr}".extraConfig = proxy.radarr;
+  };
+}

diff --git a/modules/nixos/server/services/m
edia-server/radarr.nix b/modules/nixos/serve
r/services/media-server/radarr.nix
new file mode 100644
index 0000000..beb5784
--- /dev/null
+++ b/modules/nixos/server/services/media-se
rver/radarr.nix
@@ -0,0 +1,20 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (config.ooknet.server) media-serv
er;
+  inherit (config.ooknet.server.media-serve
r) storage users groups domain proxy;
+in {
+  config = mkIf media-server.radarr.enable 
{
+    services.radarr = {
+      enable = true;
+      user = users.radarr;
+      group = groups.radarr;
+      dataDir = storage.state.radaar;
+    };
+    ooknet.server.webserver.caddy.enable = 
true;
+    services.caddy.virtualHosts."${domain.r
adarr}".extraConfig = proxy.radarr;
+  };
+}
 

diff --git a/modules/nixos/server/services/media-server/sonarr.nix b/modules/nixos
/server/services/media-server/sonarr.nix
new file mode 100644
index 0000000..be42fde
--- /dev/null
+++ b/modules/nixos/server/services/media-server/sonarr.nix
@@ -0,0 +1,20 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (config.ooknet.server) media-server;
+  inherit (config.ooknet.server.media-server) storage users groups domain proxy;
+in {
+  config = mkIf media-server.sonarr.enable {
+    services.sonarr = {
+      enable = true;
+      user = users.sonarr;
+      group = groups.sonarr;
+      dataDir = storage.state.sonarr;
+    };
+    ooknet.server.webserver.caddy.enable = true;
+    services.caddy.virtualHosts."${domain.sonarr}".extraConfig = proxy.sonarr;
+  };
+}

diff --git a/modules/nixos/server/services/m
edia-server/sonarr.nix b/modules/nixos/serve
r/services/media-server/sonarr.nix
new file mode 100644
index 0000000..be42fde
--- /dev/null
+++ b/modules/nixos/server/services/media-se
rver/sonarr.nix
@@ -0,0 +1,20 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (config.ooknet.server) media-serv
er;
+  inherit (config.ooknet.server.media-serve
r) storage users groups domain proxy;
+in {
+  config = mkIf media-server.sonarr.enable 
{
+    services.sonarr = {
+      enable = true;
+      user = users.sonarr;
+      group = groups.sonarr;
+      dataDir = storage.state.sonarr;
+    };
+    ooknet.server.webserver.caddy.enable = 
true;
+    services.caddy.virtualHosts."${domain.s
onarr}".extraConfig = proxy.sonarr;
+  };
+}
 

diff --git a/modules/nixos/server/services/media-server/transmission.nix b/modules
/nixos/server/services/media-server/transmission.nix
new file mode 100644
index 0000000..7999a19
--- /dev/null
+++ b/modules/nixos/server/services/media-server/transmission.nix
@@ -0,0 +1,77 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (builtins) concatStringsSep;
+  inherit (config.ooknet.server) media-server;
+  inherit (config.ooknet.server.media-server) storage ports users groups domain p
roxy;
+in {
+  config = mkIf media-server.transmission.enable {
+    services.transmission = {
+      enable = true;
+      package = pkgs.transmission_4;
+
+      # systemd service permissions
+      user = users.downloader;
+      group = groups.media;
+
+      # location of transmission config dir
+      home = storage.state.transmission;
+
+      # web ui
+      webHome = pkgs.flood-for-transmission;
+
+      # additional configurations
+      # see <https://github.com/transmission/transmission/blob/main/docs/Editing-
Configuration-Files.md>
+      settings = {
+        # enable in completed directory
+        # this is where files will be placed while still being downloaded
+        incomplete-dir-enabled = true;
+
+        # enable the watch directory
+        # this will look for any new torrent files and start downloading them
+        watch-dir-enabled = true;
+
+        # location of the main download directories
+        download-dir = storage.downloads.root;
+        incomplete-dir = storage.downloads.incomplete;
+        watch-dir = storage.downloads.watch;
+
+        # rpc settings
+        # rpc is how we connect to the service remotely
+        rpc-port = ports.transmission.web;
+
+        # what ip addresses are allowed to connect through rpc
+        rpc-whitelist-enabled = true;
+        rpc-whitelist = concatStringsSep "," [
+          # localhost
+          "127.0.0.1"
+          # generic home networks
+          "192.168.*"
+          "10.*"
+        ];
+
+        # basic anti bruteforce protection
+        anti-brute-force-enabled = true;
+
+        # how many authentication attempts can be made before the rpc server will
 deny any further
+        # authentication attempts.
+        anti-brute-force-threshold = 10;
+
+        peer-port = ports.transmission.peer;
+        port-forwarding-enabled = false;
+
+        # private trackers usually require disabling these
+        utp-enabled = false;
+        dht-enabled = false;
+        pex-enabled = false;
+        lpd-enabled = false;
+      };
+    };
+    ooknet.server.webserver.caddy.enable = true;
+    services.caddy.virtualHosts."${domain.transmission}".extraConfig = proxy.tran
smission;
+  };
+}

diff --git a/modules/nixos/server/services/m
edia-server/transmission.nix b/modules/nixos
/server/services/media-server/transmission.n
ix
new file mode 100644
index 0000000..7999a19
--- /dev/null
+++ b/modules/nixos/server/services/media-se
rver/transmission.nix
@@ -0,0 +1,77 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}: let
+  inherit (lib) mkIf;
+  inherit (builtins) concatStringsSep;
+  inherit (config.ooknet.server) media-serv
er;
+  inherit (config.ooknet.server.media-serve
r) storage ports users groups domain proxy;
+in {
+  config = mkIf media-server.transmission.e
nable {
+    services.transmission = {
+      enable = true;
+      package = pkgs.transmission_4;
+
+      # systemd service permissions
+      user = users.downloader;
+      group = groups.media;
+
+      # location of transmission config dir
+      home = storage.state.transmission;
+
+      # web ui
+      webHome = pkgs.flood-for-transmission
;
+
+      # additional configurations
+      # see <https://github.com/transmissio
n/transmission/blob/main/docs/Editing-Config
uration-Files.md>
+      settings = {
+        # enable in completed directory
+        # this is where files will be place
d while still being downloaded
+        incomplete-dir-enabled = true;
+
+        # enable the watch directory
+        # this will look for any new torren
t files and start downloading them
+        watch-dir-enabled = true;
+
+        # location of the main download dir
ectories
+        download-dir = storage.downloads.ro
ot;
+        incomplete-dir = storage.downloads.
incomplete;
+        watch-dir = storage.downloads.watch
;
+
+        # rpc settings
+        # rpc is how we connect to the serv
ice remotely
+        rpc-port = ports.transmission.web;
+
+        # what ip addresses are allowed to 
connect through rpc
+        rpc-whitelist-enabled = true;
+        rpc-whitelist = concatStringsSep ",
" [
+          # localhost
+          "127.0.0.1"
+          # generic home networks
+          "192.168.*"
+          "10.*"
+        ];
+
+        # basic anti bruteforce protection
+        anti-brute-force-enabled = true;
+
+        # how many authentication attempts 
can be made before the rpc server will deny 
any further
+        # authentication attempts.
+        anti-brute-force-threshold = 10;
+
+        peer-port = ports.transmission.peer
;
+        port-forwarding-enabled = false;
+
+        # private trackers usually require 
disabling these
+        utp-enabled = false;
+        dht-enabled = false;
+        pex-enabled = false;
+        lpd-enabled = false;
+      };
+    };
+    ooknet.server.webserver.caddy.enable = 
true;
+    services.caddy.virtualHosts."${domain.t
ransmission}".extraConfig = proxy.transmissi
on;
+  };
+}
 

diff --git a/modules/nixos/server/services/media-server/users.nix b/modules/nixos/
server/services/media-server/users.nix
new file mode 100644
index 0000000..6d1bcfd
--- /dev/null
+++ b/modules/nixos/server/services/media-server/users.nix
@@ -0,0 +1,23 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) elem mkIf;
+  inherit (config.ooknet.server) services;
+in {
+  config = mkIf (elem "media-server" services) {
+    users = {
+      groups = {
+        downloader = {};
+        media = {};
+      };
+      users = {
+        downloader = {
+          isSystemUser = true;
+          group = "downloader";
+        };
+      };
+    };
+  };
+}

diff --git a/modules/nixos/server/services/m
edia-server/users.nix b/modules/nixos/server
/services/media-server/users.nix
new file mode 100644
index 0000000..6d1bcfd
--- /dev/null
+++ b/modules/nixos/server/services/media-se
rver/users.nix
@@ -0,0 +1,23 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  inherit (lib) elem mkIf;
+  inherit (config.ooknet.server) services;
+in {
+  config = mkIf (elem "media-server" servic
es) {
+    users = {
+      groups = {
+        downloader = {};
+        media = {};
+      };
+      users = {
+        downloader = {
+          isSystemUser = true;
+          group = "downloader";
+        };
+      };
+    };
+  };
+}
 

diff --git a/outputs/hosts/servers.nix b/outputs/hosts/servers.nix
index a05b3cf..1902512 100644
--- a/outputs/hosts/servers.nix
+++ b/outputs/hosts/servers.nix
@@ -19,8 +19,9 @@ in {
       inherit withSystem;
       system = "x86_64-linux";
       hostname = "ooksmedia";
+      domain = "ooknet.org";
       type = "desktop";
-      services = [];
+      services = ["media-server"];
     };
   };
 }

diff --git a/outputs/hosts/servers.nix b/out
puts/hosts/servers.nix
index a05b3cf..1902512 100644
--- a/outputs/hosts/servers.nix
+++ b/outputs/hosts/servers.nix
@@ -19,8 +19,9 @@ in {
       inherit withSystem;
       system = "x86_64-linux";
       hostname = "ooksmedia";
+      domain = "ooknet.org";
       type = "desktop";
-      services = [];
+      services = ["media-server"];
     };
   };
 }
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET