2023-09-24 22:31:21 +02:00
|
|
|
{ config, pkgs, lib, ... }:
|
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.shb.arr;
|
|
|
|
|
|
|
|
apps = {
|
|
|
|
radarr = {
|
2023-09-26 08:15:36 +02:00
|
|
|
defaultPort = 7878;
|
2023-09-24 22:31:21 +02:00
|
|
|
};
|
|
|
|
sonarr = {
|
2023-09-26 08:15:36 +02:00
|
|
|
defaultPort = 8989;
|
2023-09-24 22:31:21 +02:00
|
|
|
};
|
|
|
|
bazarr = {
|
|
|
|
defaultPort = 6767;
|
|
|
|
};
|
|
|
|
readarr = {
|
|
|
|
defaultPort = 8787;
|
|
|
|
};
|
|
|
|
lidarr = {
|
|
|
|
defaultPort = 8686;
|
|
|
|
};
|
2023-10-13 07:23:58 +02:00
|
|
|
jackett = {
|
|
|
|
defaultPort = 9117;
|
|
|
|
settingsFormat = pkgs.formats.json {};
|
|
|
|
moreOptions = {
|
|
|
|
settings = lib.mkOption {
|
|
|
|
type = lib.types.submodule {
|
|
|
|
freeformType = apps.jackett.settingsFormat.type;
|
|
|
|
options = {
|
|
|
|
APIKeyFile = lib.mkOption {
|
|
|
|
type = lib.types.path;
|
|
|
|
};
|
|
|
|
FlareSolverrUrl = lib.mkOption {
|
|
|
|
type = lib.types.nullOr lib.types.str;
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
OmdbApiKeyFile = lib.mkOption {
|
|
|
|
type = lib.types.nullOr lib.types.path;
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
ProxyType = lib.mkOption {
|
|
|
|
type = lib.types.enum [ "-1" "0" "1" "2" ];
|
|
|
|
default = "0";
|
|
|
|
description = ''
|
|
|
|
-1 = disabled
|
|
|
|
0 = HTTP
|
|
|
|
1 = SOCKS4
|
|
|
|
2 = SOCKS5
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
ProxyUrl = lib.mkOption {
|
|
|
|
type = lib.types.nullOr lib.types.str;
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
ProxyPort = lib.mkOption {
|
|
|
|
type = lib.types.nullOr lib.types.port;
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
default = {};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
2023-09-24 22:31:21 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
appOption = name: c: lib.nameValuePair name (lib.mkOption {
|
|
|
|
description = "Configuration for ${name}";
|
|
|
|
type = lib.types.submodule {
|
|
|
|
options = {
|
|
|
|
enable = lib.mkEnableOption "selfhostblocks.${name}";
|
|
|
|
|
|
|
|
subdomain = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
|
|
|
description = "Subdomain under which ${name} will be served.";
|
|
|
|
example = name;
|
|
|
|
};
|
|
|
|
|
|
|
|
domain = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
|
|
|
description = "Domain under which ${name} will be served.";
|
|
|
|
example = "mydomain.com";
|
|
|
|
};
|
|
|
|
|
|
|
|
port = lib.mkOption {
|
|
|
|
type = lib.types.port;
|
|
|
|
description = "Port on which ${name} listens to incoming requests.";
|
|
|
|
default = c.defaultPort;
|
|
|
|
};
|
|
|
|
|
|
|
|
dataDir = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
|
|
|
description = "Directory where state of ${name} is stored.";
|
|
|
|
default = "/var/lib/${name}";
|
|
|
|
};
|
|
|
|
|
|
|
|
oidcEndpoint = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
|
|
|
description = "OIDC endpoint for SSO";
|
|
|
|
example = "https://authelia.example.com";
|
|
|
|
};
|
2023-10-13 07:23:58 +02:00
|
|
|
} // (c.moreOptions or {});
|
2023-09-24 22:31:21 +02:00
|
|
|
};
|
|
|
|
});
|
2023-10-13 07:23:58 +02:00
|
|
|
|
|
|
|
template = file: newPath: replacements:
|
|
|
|
let
|
|
|
|
templatePath = newPath + ".template";
|
|
|
|
|
|
|
|
sedPatterns = lib.strings.concatStringsSep " " (lib.attrsets.mapAttrsToList (from: to: "-e \"s|${from}|${to}|\"") replacements);
|
|
|
|
in
|
|
|
|
''
|
|
|
|
ln -fs ${file} ${templatePath}
|
|
|
|
rm ${newPath} || :
|
|
|
|
sed ${sedPatterns} ${templatePath} > ${newPath}
|
|
|
|
'';
|
2023-09-24 22:31:21 +02:00
|
|
|
in
|
|
|
|
{
|
|
|
|
options.shb.arr = lib.listToAttrs (lib.mapAttrsToList appOption apps);
|
|
|
|
|
2023-09-27 05:13:08 +02:00
|
|
|
config = lib.mkMerge ([
|
|
|
|
{
|
|
|
|
# Listens on port 7878
|
|
|
|
services.radarr = lib.mkIf cfg.radarr.enable {
|
|
|
|
enable = true;
|
|
|
|
dataDir = "/var/lib/radarr";
|
|
|
|
};
|
|
|
|
users.users.radarr = {
|
|
|
|
extraGroups = [ "media" ];
|
|
|
|
};
|
2023-09-24 22:31:21 +02:00
|
|
|
|
2023-09-27 05:13:08 +02:00
|
|
|
# Listens on port 8989
|
|
|
|
services.sonarr = lib.mkIf cfg.sonarr.enable {
|
|
|
|
enable = true;
|
|
|
|
dataDir = "/var/lib/sonarr";
|
|
|
|
};
|
|
|
|
users.users.sonarr = {
|
|
|
|
extraGroups = [ "media" ];
|
|
|
|
};
|
2023-09-26 08:15:36 +02:00
|
|
|
|
2023-09-27 05:13:08 +02:00
|
|
|
services.bazarr = lib.mkIf cfg.bazarr.enable {
|
|
|
|
enable = true;
|
|
|
|
listenPort = cfg.bazarr.port;
|
|
|
|
};
|
2023-09-24 22:31:21 +02:00
|
|
|
|
2023-09-27 05:13:08 +02:00
|
|
|
# Listens on port 8787
|
|
|
|
services.readarr = lib.mkIf cfg.readarr.enable {
|
|
|
|
enable = true;
|
|
|
|
dataDir = "/var/lib/readarr";
|
|
|
|
};
|
2023-09-30 08:19:39 +02:00
|
|
|
users.users.readarr = {
|
|
|
|
extraGroups = [ "media" ];
|
|
|
|
};
|
2023-09-24 22:31:21 +02:00
|
|
|
|
2023-09-27 05:13:08 +02:00
|
|
|
# Listens on port 8686
|
|
|
|
services.lidarr = lib.mkIf cfg.lidarr.enable {
|
|
|
|
enable = true;
|
|
|
|
dataDir = "/var/lib/lidarr";
|
|
|
|
};
|
2023-09-30 08:19:39 +02:00
|
|
|
users.users.lidarr = {
|
|
|
|
extraGroups = [ "media" ];
|
|
|
|
};
|
2023-09-24 22:31:21 +02:00
|
|
|
|
2023-10-13 07:23:58 +02:00
|
|
|
# Listens on port 9117
|
|
|
|
services.jackett = lib.mkIf cfg.jackett.enable {
|
|
|
|
enable = true;
|
|
|
|
dataDir = "/var/lib/jackett";
|
|
|
|
};
|
|
|
|
shb.arr.jackett.settings = {
|
|
|
|
Port = config.shb.arr.jackett.port;
|
|
|
|
AllowExternal = "false";
|
|
|
|
UpdateDisabled = "true";
|
|
|
|
};
|
|
|
|
users.users.jackett = {
|
|
|
|
extraGroups = [ "media" ];
|
|
|
|
};
|
|
|
|
systemd.services.jackett.preStart =
|
|
|
|
let
|
|
|
|
s = cfg.jackett.settings;
|
|
|
|
templatedfileSettings =
|
|
|
|
lib.optionalAttrs (!(isNull s.APIKeyFile)) {
|
|
|
|
APIKey = "%APIKEY%";
|
|
|
|
} // lib.optionalAttrs (!(isNull s.OmdbApiKeyFile)) {
|
|
|
|
OmdbApiKey = "%OMDBAPIKEY%";
|
|
|
|
};
|
|
|
|
templatedSettings = (removeAttrs s [ "APIKeyFile" "OmdbApiKeyFile" ]) // templatedfileSettings;
|
|
|
|
in
|
|
|
|
template (apps.jackett.settingsFormat.generate "jackett.json" templatedSettings) "${config.services.jackett.dataDir}/ServerConfig.json" (
|
|
|
|
lib.optionalAttrs (!(isNull s.APIKeyFile)) {
|
|
|
|
"%APIKEY%" = "$(cat ${s.APIKeyFile})";
|
|
|
|
} // lib.optionalAttrs (!(isNull s.OmdbApiKeyFile)) {
|
|
|
|
"%OMDBAPIKEY%" = "$(cat ${s.OmdbApiKeyFile})";
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2023-09-27 05:13:08 +02:00
|
|
|
shb.nginx.autheliaProtect =
|
|
|
|
let
|
|
|
|
appProtectConfig = name: _defaults:
|
|
|
|
let
|
|
|
|
c = cfg.${name};
|
|
|
|
in
|
|
|
|
{
|
|
|
|
inherit (c) subdomain domain oidcEndpoint;
|
|
|
|
upstream = "http://127.0.0.1:${toString c.port}";
|
|
|
|
autheliaRules = [
|
|
|
|
{
|
|
|
|
domain = "${c.subdomain}.${c.domain}";
|
|
|
|
policy = "bypass";
|
|
|
|
resources = [
|
|
|
|
"^/api.*"
|
2023-10-13 07:38:38 +02:00
|
|
|
] ++ lib.optionals (name == "jackett") [
|
|
|
|
"^/dl.*"
|
2023-09-27 05:13:08 +02:00
|
|
|
];
|
|
|
|
}
|
|
|
|
{
|
|
|
|
domain = "${c.subdomain}.${c.domain}";
|
|
|
|
policy = "two_factor";
|
|
|
|
subject = ["group:arr_user"];
|
|
|
|
}
|
|
|
|
];
|
2023-09-24 22:31:21 +02:00
|
|
|
};
|
2023-09-27 05:13:08 +02:00
|
|
|
in
|
|
|
|
lib.mapAttrsToList appProtectConfig apps;
|
|
|
|
|
|
|
|
shb.backup.instances =
|
|
|
|
let
|
|
|
|
backupConfig = name: _defaults: {
|
|
|
|
${name} = {
|
|
|
|
sourceDirectories = [
|
|
|
|
config.shb.arr.${name}.dataDir
|
|
|
|
];
|
|
|
|
excludePatterns = [".db-shm" ".db-wal" ".mono"];
|
2023-09-24 22:31:21 +02:00
|
|
|
};
|
|
|
|
};
|
2023-09-27 05:13:08 +02:00
|
|
|
in
|
|
|
|
lib.mkMerge (lib.mapAttrsToList backupConfig apps);
|
|
|
|
}
|
|
|
|
] ++ map (name: {
|
|
|
|
systemd.tmpfiles.rules = lib.mkIf (lib.hasAttr "dataDir" config.services.${name}) [
|
|
|
|
"d '${config.services.${name}.dataDir}' 0750 ${config.services.${name}.user} ${config.services.${name}.group} - -"
|
|
|
|
];
|
|
|
|
users.groups.${name} = {
|
|
|
|
members = [ "backup" ];
|
|
|
|
};
|
|
|
|
systemd.services.${name}.serviceConfig = {
|
|
|
|
# Setup permissions needed for backups, as the backup user is member of the jellyfin group.
|
|
|
|
UMask = lib.mkForce "0027";
|
|
|
|
StateDirectoryMode = lib.mkForce "0750";
|
|
|
|
};
|
|
|
|
}) (lib.attrNames apps));
|
2023-09-24 22:31:21 +02:00
|
|
|
}
|