ookflix: segment modules

This commit is contained in:
ooks-io 2024-12-04 13:19:54 +11:00
parent 4edb21607c
commit bee284691a
21 changed files with 314 additions and 100 deletions

View file

@ -1,15 +1,13 @@
{
imports = [
./jellyfin.nix
./plex.nix
./jellyseer.nix
./tautulli.nix
./sonarr.nix
./prowlarr.nix
./gluetun.nix
./qbittorrent.nix
./shared.nix
./streamers
./monitors
./networking
./downloading
./shared.nix
./podman.nix
./options.nix
./homepage.nix
];
}

View file

@ -0,0 +1,9 @@
{
imports = [
./sonarr.nix
./radarr.nix
./prowlarr.nix
./jellyseer.nix
./qbittorrent.nix
];
}

View file

@ -0,0 +1,38 @@
{
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;
inherit (config.ooknet.server.ookflix.services) jellyseerr;
in {
config = mkIf jellyseerr.enable {
# media requesting for jellyfin
users = mkServiceUser jellyseerr.user.name;
systemd.tmpfiles.settings.jellyseerrStateDir = mkServiceStateDir "jellyseerr";
virtualisation.oci-containers.containers = {
jellyseerr = {
image = "ghcr.io/hotio/jellyseerr";
autoStart = true;
hostname = "jellyseerr";
ports = [(mkContainerPort jellyseerr.port)];
volumes = ["${jellyseerr.stateDir}:/config"];
labels = mkContainerLabel {
name = "jellyseerr";
inherit (jellyseerr) domain port;
homepage = {
group = "media";
description = "media-server requesting";
};
};
environment = mkContainerEnvironment jellyseerr.user.id groups.media.id;
};
};
};
}

View file

@ -5,7 +5,7 @@
self,
...
}: let
ookflixLib = import ./lib.nix {inherit lib config self;};
ookflixLib = import ../lib.nix {inherit lib config self;};
inherit (ookflixLib) mkServiceUser mkServiceStateDir;
inherit (lib) mkIf;
inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainerPort;
@ -14,7 +14,7 @@
in {
config = mkIf prowlarr.enable {
users = mkServiceUser prowlarr.user.name;
systemd.tmpfiles = mkServiceStateDir "prowlarr" prowlarr.stateDir;
systemd.tmpfiles.settings.prowlarrStateDir = mkServiceStateDir "prowlarr";
virtualisation.oci-containers.containers = {
prowlarr = {
image = "lscr.io/linuxserver/prowlarr:latest";

View file

@ -5,7 +5,7 @@
self,
...
}: let
ookflixLib = import ./lib.nix {inherit lib config self;};
ookflixLib = import ../lib.nix {inherit lib config self;};
inherit (ookflixLib) mkServiceUser mkServiceStateDir;
inherit (lib) mkIf;
inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment;
@ -14,17 +14,20 @@
in {
config = mkIf qbittorrent.enable {
users = mkServiceUser qbittorrent.user.name;
systemd.tmpfiles = mkServiceStateDir "qbittorrent" qbittorrent.stateDir;
systemd.tmpfiles.settings.qbittorrentStateDir = mkServiceStateDir "qbittorrent";
virtualisation.oci-containers.containers = {
# Torrent client
qbittorrent = {
hostname = "qbittorrent";
image = "ghcr.io/hotio/qbittorrent";
dependsOn = ["gluetun"];
volumes = [
"${qbittorrent.stateDir}:/config"
"${volumes.torrents.root}:/data/torrents"
];
extraOptions = ["--network=container:gluetun"];
extraOptions = [
"--network=container:gluetun"
];
labels = mkContainerLabel {
name = "qbittorrent";
inherit (qbittorrent) port domain;
@ -34,7 +37,7 @@ in {
};
};
environment =
mkContainerEnvironment qbittorrent.user.id groups.downloads.id
mkContainerEnvironment qbittorrent.user.id groups.media.id
// {
UMASK = "002";
WEBUI_PORTS = "${toString qbittorrent.port}/tcp,${toString qbittorrent.port}/udp";

View file

@ -5,22 +5,22 @@
self,
...
}: let
ookflixLib = import ./lib.nix {inherit lib config self;};
ookflixLib = import ../lib.nix {inherit lib config self;};
inherit (ookflixLib) mkServiceUser mkServiceStateDir;
inherit (lib) mkIf;
inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment;
inherit (ook.lib.container) mkContainerLabel mkContainerPort mkContainerEnvironment;
inherit (config.ooknet.server.ookflix) groups volumes;
inherit (config.ooknet.server.ookflix.services) radarr;
in {
config = mkIf radarr.enable {
users = mkServiceUser radarr.user.name;
systemd.tmpfiles = mkServiceStateDir "radarr" radarr.stateDir;
systemd.tmpfiles.settings.radarrStateDir = mkServiceStateDir "radarr";
virtualisation.oci-containers.containers = {
radarr = {
image = "ghcr.io/hotio/qbittorrent";
image = "ghcr.io/hotio/radarr";
autoStart = true;
hostname = "radarr";
ports = ["${radarr.port}:${radarr.port}"];
ports = [(mkContainerPort radarr.port)];
volumes = [
"${radarr.stateDir}:/config"
"${volumes.data.root}:/data"

View file

@ -5,7 +5,7 @@
self,
...
}: let
ookflixLib = import ./lib.nix {inherit lib config self;};
ookflixLib = import ../lib.nix {inherit lib config self;};
inherit (ookflixLib) mkServiceUser mkServiceStateDir;
inherit (lib) mkIf;
inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainerPort;
@ -14,7 +14,7 @@
in {
config = mkIf sonarr.enable {
users = mkServiceUser sonarr.user.name;
systemd.tmpfiles = mkServiceStateDir "sonarr" sonarr.stateDir;
systemd.tmpfiles.settings.sonarrStateDir = mkServiceStateDir "sonarr";
virtualisation.oci-containers.containers = {
sonarr = {
image = "ghcr.io/hotio/sonarr";

View file

@ -0,0 +1,34 @@
{
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;
inherit (config.ooknet.server.ookflix.services) homepage;
in {
config = mkIf homepage.enable {
# media requesting for jellyfin
users = mkServiceUser homepage.user.name;
systemd.tmpfiles.settings.homepageStateDir = mkServiceStateDir "homepage";
virtualisation.oci-containers.containers = {
homepage = {
image = "ghcr.io/benphelps/homepage:latest";
autoStart = true;
hostname = "homepage";
ports = [(mkContainerPort homepage.port)];
volumes = ["${homepage.stateDir}:/config"];
labels = mkContainerLabel {
name = "homepage";
inherit (homepage) domain port;
};
environment = mkContainerEnvironment homepage.user.id groups.media.id;
};
};
};
}

View file

@ -1,34 +0,0 @@
{
config,
lib,
ook,
...
}: let
inherit (lib) mkIf;
inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainerPort;
inherit (config.ooknet.server.ookflix) groups;
inherit (config.ooknet.server.ookflix.services) jellyseer;
in {
config = mkIf jellyseer.enable {
# media requesting for jellyfin
virtualisation.oci-containers.containers = {
jellyseer = {
image = "fallenbagel/jellyseerr:latest";
autoStart = true;
hostname = "jellyseer";
ports = [(mkContainerPort jellyseer.port)];
volumes = ["${jellyseer.stateDir}:/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;
};
};
};
}

View file

@ -4,10 +4,11 @@
self,
...
}: let
inherit (lib) mkOption mkEnableOption elem assertMsg;
inherit (lib) getExe nameValuePair mkOption mkEnableOption elem assertMsg;
inherit (builtins) attrValues;
inherit (lib.types) int path port str;
inherit (config.ooknet) server;
inherit (config.virtualisation) podman;
cfg = server.ookflix;
ookflixEnabled = elem "ookflix" server.services;
@ -116,13 +117,21 @@
name = service;
};
};
mkServiceStateDir = service: dir: {
settings."${service}StateDir".${dir}."d" = {
mkServiceStateDir = service: {
"${cfg.services.${service}.stateDir}"."d" = {
mode = "0700";
user = cfg.services.${service}.user.name;
group = cfg.services.${service}.group.name;
};
};
mkServiceStateFile = service: file: {
"${cfg.services.${service}.stateDir}/${file}"."f" = {
mode = "0600";
user = cfg.services.${service}.user.name;
group = cfg.services.${service}.group.name;
};
};
mkServiceSecret = name: service: {
${name} = {
file = "${self}/secrets/containers/${name}.age";
@ -130,6 +139,17 @@
group = cfg.services.${service}.group.name;
};
};
mkNetworkService = name: network:
nameValuePair "podman-network-${name}" {
description = "Podman network ${name} for ookflix";
serviceConfig = {
Type = "oneshot";
RemainsAfterExit = true;
ExecStart = "${getExe podman.package} network create -d bridge ${name}";
ExecStop = "${getExe podman.package} network rm -f ${name}";
};
};
in {
inherit mkServiceSecret mkBasicServiceOptions mkServiceOptions mkServiceStateDir mkServiceUser mkUserOption mkPortOption mkGroupOption mkVolumeOption mkSubdomainOption;
inherit mkServiceStateFile mkServiceSecret mkBasicServiceOptions mkServiceOptions mkServiceStateDir mkServiceUser mkUserOption mkPortOption mkGroupOption mkVolumeOption mkSubdomainOption mkNetworkService;
}

View file

@ -0,0 +1,5 @@
{
imports = [
./tautulli.nix
];
}

View file

@ -5,7 +5,7 @@
self,
...
}: let
ookflixLib = import ./lib.nix {inherit lib config self;};
ookflixLib = import ../lib.nix {inherit lib config self;};
inherit (ookflixLib) mkServiceUser mkServiceStateDir;
inherit (lib) mkIf;
inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainerPort;
@ -14,7 +14,7 @@
in {
config = mkIf tautulli.enable {
users = mkServiceUser tautulli.user.name;
systemd.tmpfiles = mkServiceStateDir "tautulli" tautulli.stateDir;
systemd.tmpfiles.settings.tautulliStateDir = mkServiceStateDir "tautulli";
virtualisation.oci-containers.containers = {
# plex monitoring service
tautulli = {

View file

@ -0,0 +1,7 @@
{
imports = [
./gluetun.nix
./traefik.nix
# ./networks.nix
];
}

View file

@ -5,10 +5,10 @@
self,
...
}: let
ookflixLib = import ./lib.nix {inherit self lib config;};
ookflixLib = import ../lib.nix {inherit self lib config;};
inherit (ookflixLib) mkServiceUser mkServiceSecret;
inherit (lib) mkIf;
inherit (ook.lib.container) mkContainerEnvironment mkContainerPort;
inherit (ook.lib.container) mkContainerEnvironment;
inherit (config.ooknet.server.ookflix.services) qbittorrent gluetun;
in {
config = mkIf gluetun.enable {
@ -21,7 +21,7 @@ in {
# should make this an option.
environmentFiles = [config.age.secrets.vpn_env.path];
ports = [
(mkContainerPort qbittorrent.port)
"${toString qbittorrent.exposedPort}:${toString qbittorrent.port}"
];
environment = mkContainerEnvironment gluetun.user.id gluetun.group.id;
extraOptions = [

View file

@ -0,0 +1,28 @@
{
lib,
config,
pkgs,
...
}: let
inherit (lib) mkIf getExe;
inherit (config.ooknet.server) ookflix;
inherit (config.virtualisation) podman;
podmanCommand = getExe podman.package;
in {
config = mkIf ookflix.enable {
systemd.services = {
"podman-ookflix-network" = {
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
SyslogIdentifier = "%N";
};
unitConfig = {
"RequiresMountsFor" = "%t/containers";
};
wantedBy = ["multi-user.target"];
script = "${podmanCommand} network create --ignore --driver=bridge ookflix";
};
};
};
}

View file

@ -0,0 +1,80 @@
{
config,
lib,
ook,
self,
...
}: let
ookflixLib = import ../lib.nix {inherit self lib config;};
inherit (ookflixLib) mkServiceUser mkServiceSecret mkServiceStateDir mkServiceStateFile;
inherit (lib) mkIf;
inherit (ook.lib.container) mkContainerEnvironment mkContainerLabel mkContainerPort;
inherit (config.ooknet) server;
inherit (config.ooknet.server.ookflix.services) traefik;
inherit (config.ooknet.host) admin;
in {
config = mkIf traefik.enable {
users = mkServiceUser traefik.user.name;
systemd.tmpfiles.settings = {
traefikStateDir = mkServiceStateDir "traefik";
traefikAcmeFile = mkServiceStateFile "traefik" "acme.json";
};
age.secrets = mkServiceSecret "cf_creds" "traefik";
virtualisation.oci-containers.containers = {
# vpn container
traefik = mkIf traefik.enable {
autoStart = true;
image = "traefik:3.0";
# should make this an option.
volumes = [
"/run/podman/podman.sock:/var/run/docker.sock:ro"
"${traefik.stateDir}/acme.json:/acme.json"
];
ports = [
"80:80"
"443:443"
(mkContainerPort traefik.port)
];
environmentFiles = [config.age.secrets.cf_creds.path];
extraOptions = ["--security-opt=no-new-privileges:true"];
cmd = [
"--log.level=DEBUG"
"--api.insecure=true"
"--api.dashboard=true"
"--providers.docker=true"
"--providers.docker.exposedbydefault=false"
"--certificatesresolvers.letsencrypt.acme.email=${admin.email}"
"--certificatesresolvers.letsencrypt.acme.storage=/acme.json"
"--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
"--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare"
"--entrypoints.web.address=:80"
"--entrypoints.websecure.address=:443"
"--entrypoints.traefik.address=:${toString traefik.port}"
"--entrypoints.websecure.forwardedHeaders.trustedIPs=103.21.244.0/22,103.22.200.0/22,103.31.4.0/22" # Cloudflare IPs
"--entrypoints.web.http.redirections.entrypoint.to=websecure"
"--entrypoints.web.http.redirections.entrypoint.scheme=https"
"--entrypoints.websecure.http.tls=true"
"--entrypoints.websecure.http.tls.certResolver=letsencrypt"
"--entrypoints.websecure.http.tls.domains[0].main=${server.domain}"
"--entrypoints.websecure.http.tls.domains[0].sans=*.${server.domain}"
];
labels = mkContainerLabel {
name = "traefik";
inherit (traefik) domain port;
homepage = {
group = "proxy";
description = "reverse proxy";
};
};
environment = mkContainerEnvironment traefik.user.id traefik.group.id;
};
};
};
}

View file

@ -94,8 +94,11 @@ in {
uid = 377;
gid = 377;
}
// {torrentPort = mkPortOption 58080 "Torrenting Port for qbittorrent" 58080;};
jellyseer = mkServiceOptions "jellyseer" {
// {
torrentPort = mkPortOption 58080 "Torrenting Port for qbittorrent" 58080;
exposedPort = mkPortOption 8081 "Port exposed by qbittorrent" 8081;
};
jellyseerr = mkServiceOptions "jellyseerr" {
port = 5055;
uid = 345;
gid = 345;
@ -105,6 +108,16 @@ in {
uid = 355;
gid = 355;
};
traefik = mkServiceOptions "traefik" {
port = 8080;
uid = 389;
gid = 389;
};
homepage = mkServiceOptions "homepage" {
port = 3000;
uid = 400;
gid = 400;
};
gluetun = mkBasicServiceOptions "gluetun" {
uid = 356;
gid = 357;

View file

@ -0,0 +1,35 @@
{
lib,
config,
...
}: let
inherit (lib) mkIf;
inherit (config.ooknet.host) admin;
inherit (config.ooknet.server) ookflix;
in {
config = mkIf ookflix.enable {
# add admin to podman group
users.groups.podman.members = [admin.name];
virtualisation = {
# explicitly set this even though its the default value
# this enables the module below
oci-containers.backend = "podman";
podman = {
# periodically prunes podman resources
# defaults to --all, weekly
autoPrune.enable = true;
# aliases docker command to podman
dockerCompat = true;
# makes the podman sockaet available in place of docker socket
dockerSocket.enable = true;
# settings for containers/networks/podman.json
defaultNetwork.settings = {
# allows udp port 53 on podmans network interface: podman+
dns_enabled = true;
};
};
};
};
}

View file

@ -0,0 +1,6 @@
{
imports = [
./plex.nix
./jellyfin.nix
];
}

View file

@ -5,7 +5,7 @@
self,
...
}: let
ookflixLib = import ./lib.nix {inherit lib config self;};
ookflixLib = import ../lib.nix {inherit lib config self;};
inherit (ookflixLib) mkServiceStateDir mkServiceUser;
inherit (lib) mkIf optionalAttrs;
inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainerPort;
@ -15,7 +15,7 @@ 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;
systemd.tmpfiles.settings.jellyfinStateDir = mkServiceStateDir "jellyfin";
virtualisation.oci-containers.containers = {
# media streaming server
# docs: <https://docs.linuxserver.io/images/docker-jellyfin/>
@ -36,18 +36,6 @@ in {
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;}

View file

@ -5,7 +5,7 @@
self,
...
}: let
ookflixLib = import ./lib.nix {inherit lib config self;};
ookflixLib = import ../lib.nix {inherit lib config self;};
inherit (ookflixLib) mkServiceUser mkServiceStateDir;
inherit (lib) mkIf optionalAttrs;
inherit (ook.lib.container) mkContainerLabel mkContainerEnvironment mkContainerPort;
@ -18,7 +18,7 @@ in {
# users/group/directories configuration, see lib.nix
users = mkServiceUser plex.user.name;
systemd.tmpfiles = mkServiceStateDir "plex" plex.stateDir;
systemd.tmpfiles.settings.plexStateDir = mkServiceStateDir "plex";
# container configuration
virtualisation.oci-containers.containers = {
@ -29,8 +29,7 @@ in {
hostname = "plex";
ports = [(mkContainerPort plex.port)];
volumes = [
"${volumes.media.movies}:/data/movies"
"${volumes.media.tv}:/data/tv"
"${volumes.media.root}:/data"
"${plex.stateDir}:/config"
];
labels = mkContainerLabel {
@ -41,21 +40,6 @@ in {
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") {