ookflix: initial ookflix commit
This commit is contained in:
parent
9459f9e1f6
commit
2d437acfbb
12 changed files with 482 additions and 6 deletions
|
|
@ -14,7 +14,7 @@ in {
|
|||
description = "The server profile the host will use as a base";
|
||||
};
|
||||
services = mkOption {
|
||||
type = listOf (enum ["media-server" "website" "forgejo"]);
|
||||
type = listOf (enum ["media-server" "website" "forgejo" "ookflix"]);
|
||||
default = [];
|
||||
description = "List of services the server will host";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,5 +3,6 @@
|
|||
./website
|
||||
./forgejo
|
||||
./media-server
|
||||
./ookflix
|
||||
];
|
||||
}
|
||||
|
|
|
|||
24
modules/nixos/server/services/ookflix/default.nix
Normal file
24
modules/nixos/server/services/ookflix/default.nix
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) elem mkIf;
|
||||
inherit (config.ooknet.server) services;
|
||||
in {
|
||||
imports = [
|
||||
./jellyfin.nix
|
||||
./plex.nix
|
||||
./options.nix
|
||||
];
|
||||
|
||||
config = mkIf (elem "ookflix" services) {
|
||||
ooknet.server.ookflix = {
|
||||
gpuAcceleration.enable = true;
|
||||
services = {
|
||||
jellyfin.enable = true;
|
||||
plex.enable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
60
modules/nixos/server/services/ookflix/jellyfin.nix
Normal file
60
modules/nixos/server/services/ookflix/jellyfin.nix
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
ook,
|
||||
...
|
||||
}: let
|
||||
ookflixLib = import ./lib.nix {inherit lib config;};
|
||||
inherit (ookflixLib) mkServiceStateDir mkServiceUser;
|
||||
inherit (lib) mkIf optionalAttrs;
|
||||
inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainerPort;
|
||||
inherit (config.ooknet.server.ookflix) volumes services groups gpuAcceleration;
|
||||
inherit (config.ooknet.server.ookflix.services) jellyfin;
|
||||
in {
|
||||
config = mkIf services.jellyfin.enable {
|
||||
hardware.nvidia-container-toolkit.enable = gpuAcceleration.enable && gpuAcceleration.type == "nvidia";
|
||||
users = mkServiceUser jellyfin.user.name;
|
||||
systemd.tmpfiles = mkServiceStateDir "jellyfin" jellyfin.stateDir;
|
||||
virtualisation.oci-containers.containers = {
|
||||
# media streaming server
|
||||
# docs: <https://docs.linuxserver.io/images/docker-jellyfin/>
|
||||
jellyfin = {
|
||||
image = "lscr.io/linuxserver/jellyfin:latest";
|
||||
autoStart = true;
|
||||
hostname = "jellyfin";
|
||||
ports = [(mkContainerPort jellyfin.port)];
|
||||
volumes = [
|
||||
"${volumes.media.movies}:/data/movies"
|
||||
"${volumes.media.tv}:/data/tv"
|
||||
"${jellyfin.stateDir}:/config"
|
||||
];
|
||||
labels = mkContainerLabel {
|
||||
name = "jellyfin";
|
||||
inherit (jellyfin) port domain;
|
||||
homepage = {
|
||||
group = "media";
|
||||
description = "media-server streamer";
|
||||
};
|
||||
};
|
||||
|
||||
extraOptions = optionalAttrs gpuAcceleration.enable (
|
||||
if gpuAcceleration.type == "nvidia"
|
||||
then [
|
||||
"--runtime=nvidia"
|
||||
]
|
||||
else if gpuAcceleration.type == "intel" || "amd"
|
||||
then [
|
||||
"--device=/dev/dri:/dev/dri"
|
||||
]
|
||||
else []
|
||||
);
|
||||
environment =
|
||||
mkContainerEnvironment jellyfin.user.id groups.media.id
|
||||
// {JELLYFIN_PublishedServerUrl = jellyfin.domain;}
|
||||
// optionalAttrs (gpuAcceleration.enable && gpuAcceleration.type == "nvidia") {
|
||||
NVIDIA_VISIBLE_DEVICES = "all";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
32
modules/nixos/server/services/ookflix/jellyseer.nix
Normal file
32
modules/nixos/server/services/ookflix/jellyseer.nix
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
ook,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainerPort;
|
||||
inherit (config.ooknet.server.ookflix) storage groups;
|
||||
inherit (config.ooknet.server.ookflix.services) jellyseer;
|
||||
in {
|
||||
config = mkIf jellyseer.enable {
|
||||
# media requesting for jellyfin
|
||||
jellyseer = {
|
||||
image = "fallenbagel/jellyseerr:latest";
|
||||
autoStart = true;
|
||||
hostname = "jellyseer";
|
||||
ports = [(mkContainerPort jellyseer.port)];
|
||||
volumes = ["${storage.state.jellyseer}:/config"];
|
||||
extraOptions = ["--network" "host"];
|
||||
labels = mkContainerLabel {
|
||||
name = "jellyseer";
|
||||
inherit (jellyseer) domain port;
|
||||
homepage = {
|
||||
group = "media";
|
||||
description = "media-server requesting";
|
||||
};
|
||||
};
|
||||
environment = mkContainerEnvironment jellyseer.user.id groups.media.id;
|
||||
};
|
||||
};
|
||||
}
|
||||
111
modules/nixos/server/services/ookflix/lib.nix
Normal file
111
modules/nixos/server/services/ookflix/lib.nix
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkOption mkEnableOption elem assertMsg;
|
||||
inherit (builtins) attrValues;
|
||||
inherit (lib.types) int path port str;
|
||||
inherit (config.ooknet) server;
|
||||
cfg = server.ookflix;
|
||||
|
||||
mkSubdomainOption = name: description: example:
|
||||
mkOption {
|
||||
type = str;
|
||||
default = "${name}.${server.domain}";
|
||||
inherit description example;
|
||||
};
|
||||
|
||||
# check config.ids for static uid/gid based on service name, if available use that, if not, use fallback.
|
||||
# check fallback doesnt conflict with existing static id
|
||||
getId = idType: name: fallback: let
|
||||
allNixosIds = attrValues config.ids.${idType};
|
||||
fallbackConflict = elem fallback allNixosIds;
|
||||
in
|
||||
mkOption {
|
||||
type = int;
|
||||
default =
|
||||
config.ids.${idType}.${name}
|
||||
or (
|
||||
assert assertMsg (!fallbackConflict)
|
||||
"Fallback ${idType} ${toString fallback} for ${name} conflicts with NixOS static allocation"; fallback
|
||||
);
|
||||
description = "${idType} of ${name} container";
|
||||
example = 224;
|
||||
};
|
||||
|
||||
mkUserOption = name: fallback: {
|
||||
name = mkOption {
|
||||
type = str;
|
||||
default = name;
|
||||
description = "Name of ${name} container user";
|
||||
example = "${name}";
|
||||
};
|
||||
id = getId "uids" name fallback;
|
||||
};
|
||||
|
||||
mkGroupOption = name: fallback: {
|
||||
name = mkOption {
|
||||
type = str;
|
||||
default = name;
|
||||
};
|
||||
id = getId "gids" name fallback;
|
||||
};
|
||||
|
||||
mkPortOption = value: description: example:
|
||||
mkOption {
|
||||
type = port;
|
||||
default = value;
|
||||
inherit description example;
|
||||
};
|
||||
|
||||
mkVolumeOption = type: pathValue:
|
||||
mkOption {
|
||||
type = path;
|
||||
default =
|
||||
if type == "state"
|
||||
then "${cfg.volumes.state.root}/${pathValue}"
|
||||
else if type == "media"
|
||||
then "${cfg.volumes.media.root}/${pathValue}"
|
||||
else if type == "downloads"
|
||||
then "${cfg.volumes.downloads.root}/${pathValue}"
|
||||
else if type == "root"
|
||||
then pathValue
|
||||
else throw "Invalid VolumeOption type: ${type}. Must be one of 'state' 'media' 'downloads' 'root'";
|
||||
};
|
||||
|
||||
mkServiceOptions = name: {
|
||||
port,
|
||||
gid,
|
||||
uid,
|
||||
...
|
||||
} @ args: {
|
||||
enable = mkEnableOption "Enable ${name} container";
|
||||
port = mkPortOption args.port "Port for ${name} container." 80;
|
||||
domain = mkSubdomainOption name "Domain for ${name} container." "${name}.mydomain.com";
|
||||
stateDir = mkVolumeOption "state" name;
|
||||
user = mkUserOption name args.uid;
|
||||
group = mkGroupOption name args.gid;
|
||||
};
|
||||
mkServiceUser = service: {
|
||||
users.${service} = {
|
||||
isSystemUser = true;
|
||||
uid = cfg.services.${service}.user.id;
|
||||
name = service;
|
||||
group = service;
|
||||
};
|
||||
groups.${service} = {
|
||||
gid = cfg.services.${service}.group.id;
|
||||
name = service;
|
||||
};
|
||||
};
|
||||
mkServiceStateDir = service: dir: {
|
||||
settings."${service}StateDir".${dir}."d" = {
|
||||
mode = "0700";
|
||||
user = cfg.services.${service}.user.name;
|
||||
group = cfg.services.${service}.group.name;
|
||||
};
|
||||
};
|
||||
in {
|
||||
inherit mkServiceOptions mkServiceStateDir mkServiceUser mkUserOption mkPortOption mkGroupOption mkVolumeOption mkSubdomainOption;
|
||||
}
|
||||
92
modules/nixos/server/services/ookflix/options.nix
Normal file
92
modules/nixos/server/services/ookflix/options.nix
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
ookflixLib = import ./lib.nix {inherit lib config;};
|
||||
|
||||
inherit (ookflixLib) mkVolumeOption mkGroupOption mkServiceOptions;
|
||||
inherit (lib) mkOption mkEnableOption;
|
||||
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";
|
||||
gpuAcceleration = {
|
||||
enable = mkEnableOption "Enable GPU acceleration for video streamers";
|
||||
type = mkOption {
|
||||
type = enum ["nvidia" "intel" "amd"];
|
||||
default = config.ooknet.hardware.gpu.type;
|
||||
description = ''
|
||||
What GPU type to use for GPU acceleration.
|
||||
Defaults to system GPU type (ooknet.hardware.gpu.type)
|
||||
'';
|
||||
};
|
||||
};
|
||||
volumes = {
|
||||
state.root = mkVolumeOption "root" "/var/lib/ookflix";
|
||||
content.root = mkVolumeOption "root" "/jellyfin";
|
||||
downloads = {
|
||||
root = mkVolumeOption "${cfg.content.root}/downloads";
|
||||
incomplete = mkVolumeOption "downloads" "incomplete";
|
||||
complete = mkVolumeOption "downloads" "complete";
|
||||
watch = mkVolumeOption "downloads" "watch";
|
||||
};
|
||||
|
||||
media = {
|
||||
root = mkVolumeOption "root" "${cfg.volumes.content.root}/media";
|
||||
movies = mkVolumeOption "media" "movies";
|
||||
tv = mkVolumeOption "media" "tv";
|
||||
};
|
||||
};
|
||||
# Shared groups
|
||||
groups = {
|
||||
media = mkGroupOption "media" 992;
|
||||
downloader = mkGroupOption "downloader" 981;
|
||||
};
|
||||
|
||||
services = {
|
||||
jellyfin = mkServiceOptions "jellyfin" {
|
||||
port = 8096;
|
||||
uid = 994;
|
||||
gid = 994;
|
||||
};
|
||||
plex = mkServiceOptions "plex" {
|
||||
port = 32400;
|
||||
uid = 195;
|
||||
gid = 195;
|
||||
};
|
||||
sonarr = mkServiceOptions "sonarr" {
|
||||
port = 8989;
|
||||
uid = 274;
|
||||
gid = 274;
|
||||
};
|
||||
radarr = mkServiceOptions "radarr" {
|
||||
port = 7878;
|
||||
uid = 275;
|
||||
gid = 275;
|
||||
};
|
||||
prowlarr = mkServiceOptions "prowlarr" {
|
||||
port = 9696;
|
||||
uid = 982;
|
||||
gid = 987;
|
||||
};
|
||||
transmission = mkServiceOptions "transmission" {
|
||||
port = 9091;
|
||||
uid = 70;
|
||||
gid = 70;
|
||||
};
|
||||
jellyseer = mkServiceOptions "jellyseer" {
|
||||
port = 5055;
|
||||
uid = 345;
|
||||
gid = 345;
|
||||
};
|
||||
tautulli = mkServiceOptions "tautulli" {
|
||||
port = 8181;
|
||||
uid = 355;
|
||||
gid = 355;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
66
modules/nixos/server/services/ookflix/plex.nix
Normal file
66
modules/nixos/server/services/ookflix/plex.nix
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
ook,
|
||||
...
|
||||
}: let
|
||||
ookflixLib = import ./lib.nix {inherit lib config;};
|
||||
inherit (ookflixLib) mkServiceUser mkServiceStateDir;
|
||||
inherit (lib) mkIf optionalAttrs;
|
||||
inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainerPort;
|
||||
inherit (config.ooknet.server.ookflix) gpuAcceleration services volumes groups;
|
||||
inherit (config.ooknet.server.ookflix.services) plex;
|
||||
in {
|
||||
config = mkIf plex.enable {
|
||||
# not sure if this is needed for podman
|
||||
hardware.nvidia-container-toolkit.enable = gpuAcceleration.enable && gpuAcceleration.type == "nvidia";
|
||||
|
||||
# users/group/directories configuration, see lib.nix
|
||||
users = mkServiceUser plex.user.name;
|
||||
systemd.tmpfiles = mkServiceStateDir "plex" plex.stateDir;
|
||||
|
||||
# container configuration
|
||||
virtualisation.oci-containers.containers = {
|
||||
# media streaming server
|
||||
plex = {
|
||||
image = "lscr.io/linuxserver/plex:latest";
|
||||
autoStart = true;
|
||||
hostname = "plex";
|
||||
ports = [(mkContainerPort plex.port)];
|
||||
volumes = [
|
||||
"${volumes.media.movies}:/data/movies"
|
||||
"${volumes.media.tv}:/data/tv"
|
||||
"${plex.stateDir}:/config"
|
||||
];
|
||||
labels = mkContainerLabel {
|
||||
name = "plex";
|
||||
inherit (plex) domain port;
|
||||
homepage = {
|
||||
group = "media";
|
||||
description = "media-server streamer";
|
||||
};
|
||||
};
|
||||
extraOptions = optionalAttrs gpuAcceleration.enable (
|
||||
if gpuAcceleration.type == "nvidia"
|
||||
then [
|
||||
"--runtime=nvidia"
|
||||
]
|
||||
else if gpuAcceleration.type == "intel"
|
||||
then [
|
||||
"--device=/dev/dri:/dev/dri"
|
||||
]
|
||||
else if gpuAcceleration.type == "amd"
|
||||
then [
|
||||
"--device=/dev/dri:/dev/dri"
|
||||
]
|
||||
else []
|
||||
);
|
||||
environment =
|
||||
mkContainerEnvironment plex.user.id groups.media.id
|
||||
// optionalAttrs (gpuAcceleration.enable && gpuAcceleration.type == "nvidia") {
|
||||
NVIDIA_VISIBLE_DEVICES = "all";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
37
modules/nixos/server/services/ookflix/tautulli.nix
Normal file
37
modules/nixos/server/services/ookflix/tautulli.nix
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
ook,
|
||||
...
|
||||
}: let
|
||||
ookflixLib = import ./lib.nix {inherit lib config;};
|
||||
inherit (ookflixLib) mkServiceUser mkServiceStateDir;
|
||||
inherit (lib) mkIf;
|
||||
inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainerPort;
|
||||
inherit (config.ooknet.server.ookflix) groups;
|
||||
inherit (config.ooknet.server.services) tautulli;
|
||||
in {
|
||||
config = mkIf tautulli.enable {
|
||||
users = mkServiceUser tautulli.user.name;
|
||||
systemd.tmpfiles = mkServiceStateDir "tautulli" tautulli.stateDir;
|
||||
virtualisation.oci-containers.containers = {
|
||||
# plex monitoring service
|
||||
tautulli = {
|
||||
image = "lscr.io/linuxserver/tautulli:latest";
|
||||
autoStart = true;
|
||||
hostname = "tautulli";
|
||||
ports = [(mkContainerPort tautulli.port)];
|
||||
volumes = ["${tautulli.stateDir}:/config"];
|
||||
labels = mkContainerLabel {
|
||||
name = "tautulli";
|
||||
inherit (tautulli) port domain;
|
||||
homepage = {
|
||||
group = "monitoring";
|
||||
description = "media-server monitoring";
|
||||
};
|
||||
};
|
||||
environment = mkContainerEnvironment tautulli.user.id groups.media.id;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
38
modules/nixos/server/services/ookflix/users.nix
Normal file
38
modules/nixos/server/services/ookflix/users.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf mkMerge;
|
||||
inherit (builtins) mapAttrs;
|
||||
inherit (config.ooknet.server) ookflix;
|
||||
inherit (config.ooknet.server.ookflix) services storage users groups;
|
||||
|
||||
mkServiceUser = name: user: {
|
||||
isSystemUser = true;
|
||||
group = groups.${name}.name;
|
||||
uid = users.${name}.id;
|
||||
home = storage.state.${name};
|
||||
};
|
||||
|
||||
generateUsers = mapAttrs mkServiceUser users;
|
||||
in {
|
||||
config = mkIf ookflix.enable {
|
||||
users = {
|
||||
users = mkMerge [
|
||||
# media service users
|
||||
(mkIf services.jellyfin.enable {
|
||||
${users.jellyfin.name} = mkServiceUser users.jellyfin.name groups.media.name;
|
||||
})
|
||||
(mkIf services.plex.enable {
|
||||
${users.plex.name} = mkServiceUser users.plex.name groups.media.name;
|
||||
})
|
||||
(mkIf (services.jellyfin.enable || services.jellyseer.enable) {
|
||||
${users.jellyseer.name} = mkServiceUser users.jellyseer.name groups.media.name;
|
||||
})
|
||||
];
|
||||
groups = {
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue