432 lines
12 KiB
Nix
432 lines
12 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
let
|
|
cfg = config.homelab.apps.arr;
|
|
|
|
networkName = "arrStack";
|
|
proxyNet = config.homelab.apps.traefik.sharedNetworkName;
|
|
|
|
appNames = [ "bazarr" "lidarr" "prowlarr" "qbittorrent" "radarr" "sonarr" ];
|
|
inUse = builtins.any (app: cfg.${app}.enable) appNames;
|
|
|
|
PGID = toString config.users.groups.media.gid;
|
|
UMASK = "002";
|
|
in {
|
|
options.homelab.apps.arr = {
|
|
enable = lib.mkEnableOption "Arr Stack using Docker";
|
|
|
|
bazarr.enable = lib.mkEnableOption "Bazarr using Docker";
|
|
lidarr.enable = lib.mkEnableOption "Lidarr using Docker";
|
|
prowlarr.enable = lib.mkEnableOption "Prowlarr using Docker";
|
|
qbittorrent.enable = lib.mkEnableOption "qBittorrent using Docker";
|
|
radarr.enable = lib.mkEnableOption "Radarr using Docker";
|
|
sonarr.enable = lib.mkEnableOption "Sonarr using Docker";
|
|
};
|
|
|
|
config = {
|
|
homelab = {
|
|
users = lib.mkIf inUse {
|
|
apps.enable = true;
|
|
media.enable = true;
|
|
};
|
|
|
|
# "Master switch": Enable all apps.
|
|
apps.arr = lib.mkIf cfg.enable {
|
|
bazarr.enable = true;
|
|
lidarr.enable = true;
|
|
prowlarr.enable = true;
|
|
qbittorrent.enable = true;
|
|
radarr.enable = true;
|
|
sonarr.enable = true;
|
|
};
|
|
|
|
fileSystems.media.video = {
|
|
enable = true;
|
|
permissions = [ "read" "write" ];
|
|
};
|
|
|
|
virtualisation.containers.enable = lib.mkIf inUse true;
|
|
};
|
|
|
|
fileSystems = lib.mkIf inUse {
|
|
"/srv/bazarr-backup" = lib.mkIf cfg.bazarr.enable {
|
|
device = "192.168.0.11:/mnt/BIG/BACKUP/BAZARR";
|
|
fsType = "nfs";
|
|
options = [
|
|
"rw"
|
|
"auto"
|
|
"nfsvers=4.2"
|
|
"rsize=1048576" "wsize=1048576"
|
|
"hard"
|
|
"timeo=600" "retrans=2"
|
|
"_netdev" "nosuid" "tcp"
|
|
];
|
|
};
|
|
|
|
"/srv/lidarr-backup" = lib.mkIf cfg.lidarr.enable {
|
|
device = "192.168.0.11:/mnt/BIG/BACKUP/LIDARR";
|
|
fsType = "nfs";
|
|
options = [
|
|
"rw"
|
|
"auto"
|
|
"nfsvers=4.2"
|
|
"rsize=1048576" "wsize=1048576"
|
|
"hard"
|
|
"timeo=600" "retrans=2"
|
|
"_netdev" "nosuid" "tcp"
|
|
];
|
|
};
|
|
|
|
"/srv/prowlarr-backup" = lib.mkIf cfg.prowlarr.enable {
|
|
device = "192.168.0.11:/mnt/BIG/BACKUP/PROWLARR";
|
|
fsType = "nfs";
|
|
options = [
|
|
"rw"
|
|
"auto"
|
|
"nfsvers=4.2"
|
|
"rsize=1048576" "wsize=1048576"
|
|
"hard"
|
|
"timeo=600" "retrans=2"
|
|
"_netdev" "nosuid" "tcp"
|
|
];
|
|
};
|
|
|
|
"/srv/qbittorrent" = lib.mkIf cfg.qbittorrent.enable {
|
|
device = "192.168.0.11:/mnt/SMALL/CONFIG/QBITTORRENT";
|
|
fsType = "nfs";
|
|
options = [
|
|
"rw"
|
|
"auto"
|
|
"nfsvers=4.2"
|
|
"rsize=1048576" "wsize=1048576"
|
|
"hard"
|
|
"timeo=600" "retrans=2"
|
|
"_netdev" "nosuid" "tcp"
|
|
];
|
|
};
|
|
|
|
"/srv/radarr-backup" = lib.mkIf cfg.radarr.enable {
|
|
device = "192.168.0.11:/mnt/BIG/BACKUP/RADARR";
|
|
fsType = "nfs";
|
|
options = [
|
|
"rw"
|
|
"auto"
|
|
"nfsvers=4.2"
|
|
"rsize=1048576" "wsize=1048576"
|
|
"hard"
|
|
"timeo=600" "retrans=2"
|
|
"_netdev" "nosuid" "tcp"
|
|
];
|
|
};
|
|
|
|
"/srv/sonarr-backup" = lib.mkIf cfg.sonarr.enable {
|
|
device = "192.168.0.11:/mnt/BIG/BACKUP/SONARR";
|
|
fsType = "nfs";
|
|
options = [
|
|
"rw"
|
|
"auto"
|
|
"nfsvers=4.2"
|
|
"rsize=1048576" "wsize=1048576"
|
|
"hard"
|
|
"timeo=600" "retrans=2"
|
|
"_netdev" "nosuid" "tcp"
|
|
];
|
|
};
|
|
|
|
"/srv/torrent" = {
|
|
device = "192.168.0.11:/mnt/SMALL/MEDIA/TORRENT";
|
|
fsType = "nfs";
|
|
options = [
|
|
"rw"
|
|
"auto"
|
|
"nfsvers=4.2"
|
|
"rsize=1048576" "wsize=1048576"
|
|
"hard"
|
|
"timeo=600" "retrans=2"
|
|
"_netdev" "nosuid" "tcp"
|
|
];
|
|
};
|
|
};
|
|
|
|
# Make sure the Docker network exists.
|
|
systemd.services."docker-${networkName}-create-network" = lib.mkIf inUse {
|
|
description = "Create Docker network for ${networkName}";
|
|
requiredBy = [
|
|
"docker-bazarr.service"
|
|
"docker-lidarr.service"
|
|
"docker-prowlarr.service"
|
|
"docker-qbittorrent.service"
|
|
"docker-radarr.service"
|
|
"docker-sonarr.service"
|
|
];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
};
|
|
script = ''
|
|
if ! ${pkgs.docker}/bin/docker network ls | grep -q ${networkName}; then
|
|
${pkgs.docker}/bin/docker network create ${networkName}
|
|
fi
|
|
'';
|
|
};
|
|
|
|
# Create a user for each app.
|
|
users.users = {
|
|
bazarr = lib.mkIf cfg.bazarr.enable {
|
|
uid = lib.mkForce 3003;
|
|
isSystemUser = true;
|
|
group = config.users.groups.media.name;
|
|
home = "/var/empty";
|
|
shell = null;
|
|
};
|
|
lidarr = lib.mkIf cfg.lidarr.enable {
|
|
uid = lib.mkForce 3002;
|
|
isSystemUser = true;
|
|
group = config.users.groups.media.name;
|
|
home = "/var/empty";
|
|
shell = null;
|
|
};
|
|
prowlarr = lib.mkIf cfg.prowlarr.enable {
|
|
uid = lib.mkForce 3004;
|
|
isSystemUser = true;
|
|
group = config.users.groups.media.name;
|
|
home = "/var/empty";
|
|
shell = null;
|
|
};
|
|
qbittorrent = lib.mkIf cfg.qbittorrent.enable {
|
|
uid = lib.mkForce 3005;
|
|
isSystemUser = true;
|
|
group = config.users.groups.media.name;
|
|
extraGroups = [
|
|
config.users.groups.apps.name
|
|
];
|
|
home = "/var/empty";
|
|
shell = null;
|
|
};
|
|
radarr = lib.mkIf cfg.radarr.enable {
|
|
uid = lib.mkForce 3006;
|
|
isSystemUser = true;
|
|
group = config.users.groups.media.name;
|
|
home = "/var/empty";
|
|
shell = null;
|
|
};
|
|
sonarr = lib.mkIf cfg.sonarr.enable {
|
|
uid = lib.mkForce 3007;
|
|
isSystemUser = true;
|
|
group = config.users.groups.media.name;
|
|
home = "/var/empty";
|
|
shell = null;
|
|
};
|
|
};
|
|
|
|
virtualisation.oci-containers.containers = let
|
|
videoHostPath = config.homelab.fileSystems.media.video.hostPath;
|
|
in {
|
|
bazarr = let
|
|
port = 6767;
|
|
in lib.mkIf cfg.bazarr.enable {
|
|
hostname = "bazarr";
|
|
image = "ghcr.io/hotio/bazarr:release-1.4.4";
|
|
autoStart = true;
|
|
ports = [
|
|
# Open ports if you don't use Traefik
|
|
# "${toString port}:${toString port}/tcp"
|
|
# "${toString port}:${toString port}/udp"
|
|
];
|
|
extraOptions = [
|
|
"--network=${networkName}"
|
|
"--network=${proxyNet}"
|
|
];
|
|
environment = {
|
|
PUID = toString config.users.users.bazarr.uid;
|
|
inherit PGID UMASK;
|
|
TZ = config.time.timeZone;
|
|
WEBUI_PORTS = "${toString port}/tcp,${toString port}/udp";
|
|
};
|
|
volumes = [
|
|
"bazarr-config:/config"
|
|
|
|
"/srv/bazarr-backup:/config/backup"
|
|
|
|
"${videoHostPath}/Films:/media/movies"
|
|
"${videoHostPath}/Series:/media/series"
|
|
];
|
|
labels = {
|
|
"traefik.enable" = "true";
|
|
"traefik.docker.network" = proxyNet;
|
|
"traefik.http.routers.bazarr.rule" = "Host(`bazarr.depeuter.dev`)";
|
|
"traefik.http.services.bazarr.loadbalancer.server.port" = toString port;
|
|
};
|
|
};
|
|
|
|
lidarr = let
|
|
port = 8686;
|
|
in lib.mkIf cfg.lidarr.enable {
|
|
hostname = "lidarr";
|
|
image = "ghcr.io/hotio/lidarr:release-2.5.3.4341";
|
|
autoStart = true;
|
|
ports = [
|
|
# Open ports if you don't use Traefik
|
|
# "${toString port}:${toString port}/tcp"
|
|
];
|
|
extraOptions = [
|
|
"--network=${networkName}"
|
|
"--network=${proxyNet}"
|
|
];
|
|
environment = {
|
|
PUID = toString config.users.users.lidarr.uid;
|
|
inherit PGID UMASK;
|
|
TZ = config.time.timeZone;
|
|
};
|
|
volumes = [
|
|
"lidarr-config:/config"
|
|
|
|
# TODO Fix path
|
|
"/srv/lidarr-backup:/media/Backups"
|
|
];
|
|
labels = {
|
|
"traefik.enable" = "true";
|
|
"traefik.docker.network" = proxyNet;
|
|
"traefik.http.routers.lidarr.rule" = "Host(`lidarr.depeuter.dev`)";
|
|
"traefik.http.services.lidarr.loadbalancer.server.port" = toString port;
|
|
};
|
|
};
|
|
|
|
prowlarr = let
|
|
port = 9696;
|
|
in lib.mkIf cfg.prowlarr.enable {
|
|
hostname = "prowlarr";
|
|
image = "ghcr.io/hotio/prowlarr:release-1.23.1.4708";
|
|
autoStart = true;
|
|
ports = [
|
|
# Open ports if you don't use Traefik
|
|
# "${toString port}:${toString port}/tcp"
|
|
];
|
|
extraOptions = [
|
|
"--network=${networkName}"
|
|
"--network=${proxyNet}"
|
|
];
|
|
environment = {
|
|
PUID = toString config.users.users.prowlarr.uid;
|
|
inherit PGID UMASK;
|
|
TZ = config.time.timeZone;
|
|
};
|
|
volumes = [
|
|
"prowlarr-config:/config"
|
|
|
|
"/srv/prowlarr-backup:/config/Backups"
|
|
];
|
|
labels = {
|
|
"traefik.enable" = "true";
|
|
"traefik.docker.network" = proxyNet;
|
|
"traefik.http.routers.prowlarr.rule" = "Host(`prowlarr.depeuter.dev`)";
|
|
"traefik.http.services.prowlarr.loadbalancer.server.port" = toString port;
|
|
};
|
|
};
|
|
|
|
qbittorrent = let
|
|
port = 10095;
|
|
in lib.mkIf cfg.qbittorrent.enable {
|
|
hostname = "qbittorrent";
|
|
image = "ghcr.io/hotio/qbittorrent:release-4.6.7";
|
|
autoStart = true;
|
|
ports = [
|
|
# Open ports if you don't use Traefik
|
|
# "${toString port}:${toString port}/tcp"
|
|
# "${toString port}:${toString port}/udp"
|
|
];
|
|
extraOptions = [
|
|
"--network=${networkName}"
|
|
"--network=${proxyNet}"
|
|
];
|
|
environment = {
|
|
PUID = toString config.users.users.qbittorrent.uid;
|
|
inherit PGID UMASK;
|
|
TZ = config.time.timeZone;
|
|
WEBUI_PORTS = "${toString port}/tcp,${toString port}/udp";
|
|
};
|
|
volumes = [
|
|
"/srv/qbittorrent:/config"
|
|
|
|
"/srv/torrent:/media/cache"
|
|
];
|
|
labels = {
|
|
"traefik.enable" = "true";
|
|
"traefik.docker.network" = proxyNet;
|
|
"traefik.http.routers.qbittorrent.rule" = "Host(`qb.depeuter.dev`)";
|
|
"traefik.http.services.qbittorrent.loadbalancer.server.port" = toString port;
|
|
};
|
|
};
|
|
|
|
radarr = let
|
|
port = 7878;
|
|
in lib.mkIf cfg.radarr.enable {
|
|
hostname = "radarr";
|
|
image = "ghcr.io/hotio/radarr:release-5.9.1.9070";
|
|
autoStart = true;
|
|
ports = [
|
|
# Open ports if you don't use Traefik
|
|
# "${toString port}:${toString port}/tcp"
|
|
];
|
|
extraOptions = [
|
|
"--network=${networkName}"
|
|
"--network=${proxyNet}"
|
|
];
|
|
environment = {
|
|
PUID = toString config.users.users.radarr.uid;
|
|
inherit PGID UMASK;
|
|
TZ = config.time.timeZone;
|
|
};
|
|
volumes = [
|
|
"radarr-config:/config"
|
|
|
|
"/srv/radarr-backup:/config/Backups"
|
|
|
|
"/srv/torrent:/media/cache"
|
|
"${videoHostPath}/Films:/media/movies"
|
|
];
|
|
labels = {
|
|
"traefik.enable" = "true";
|
|
"traefik.docker.network" = proxyNet;
|
|
"traefik.http.routers.radarr.rule" = "Host(`radarr.depeuter.dev`)";
|
|
"traefik.http.services.radarr.loadbalancer.server.port" = toString port;
|
|
};
|
|
};
|
|
|
|
sonarr = let
|
|
port = 8989;
|
|
in lib.mkIf cfg.sonarr.enable {
|
|
hostname = "sonarr";
|
|
image = "ghcr.io/hotio/sonarr:release-4.0.9.2244";
|
|
autoStart = true;
|
|
ports = [
|
|
# Open ports if you don't use Traefik
|
|
# "${toString port}:${toString port}/tcp"
|
|
];
|
|
extraOptions = [
|
|
"--network=${networkName}"
|
|
"--network=${proxyNet}"
|
|
];
|
|
environment = {
|
|
PUID = toString config.users.users.sonarr.uid;
|
|
inherit PGID UMASK;
|
|
TZ = config.time.timeZone;
|
|
};
|
|
volumes = [
|
|
"sonarr-config:/config"
|
|
|
|
"/srv/sonarr-backup:/config/Backups"
|
|
|
|
"/srv/torrent:/media/cache"
|
|
"${videoHostPath}/Series:/media/series"
|
|
];
|
|
labels = {
|
|
"traefik.enable" = "true";
|
|
"traefik.docker.network" = proxyNet;
|
|
"traefik.http.routers.sonarr.rule" = "Host(`sonarr.depeuter.dev`)";
|
|
"traefik.http.services.sonarr.loadbalancer.server.port" = toString port;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|