mirror of
https://github.com/nmasur/dotfiles
synced 2025-07-06 21:20:13 +00:00
move encrypted secrets near relevant files
This commit is contained in:
289
platforms/nixos/modules/nmasur/presets/services/arr/arr.nix
Normal file
289
platforms/nixos/modules/nmasur/presets/services/arr/arr.nix
Normal file
@ -0,0 +1,289 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
|
||||
inherit (config.nmasur.settings) hostnames;
|
||||
cfg = config.nmasur.presets.services.arrs;
|
||||
|
||||
# This config specifies ports for Prometheus to scrape information
|
||||
arrConfig = {
|
||||
radarr = {
|
||||
exportarrPort = "9707";
|
||||
url = "localhost:7878";
|
||||
apiKey = config.secrets.radarrApiKey.dest;
|
||||
};
|
||||
readarr = {
|
||||
exportarrPort = "9711";
|
||||
url = "localhost:8787";
|
||||
apiKey = config.secrets.readarrApiKey.dest;
|
||||
};
|
||||
sonarr = {
|
||||
exportarrPort = "9708";
|
||||
url = "localhost:8989";
|
||||
apiKey = config.secrets.sonarrApiKey.dest;
|
||||
};
|
||||
prowlarr = {
|
||||
exportarrPort = "9709";
|
||||
url = "localhost:9696";
|
||||
apiKey = config.secrets.prowlarrApiKey.dest;
|
||||
};
|
||||
sabnzbd = {
|
||||
exportarrPort = "9710";
|
||||
url = "localhost:8085";
|
||||
apiKey = config.secrets.sabnzbdApiKey.dest;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
|
||||
options.nmasur.presets.services.arrs.enable = lib.mkEnableOption "Arr services";
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
# Required
|
||||
nmasur.profiles.shared-media.enable = true; # Shared user for multiple services
|
||||
|
||||
# # Broken on 2024-12-07
|
||||
# # https://discourse.nixos.org/t/solved-sonarr-is-broken-in-24-11-unstable-aka-how-the-hell-do-i-use-nixpkgs-config-permittedinsecurepackages/
|
||||
# insecurePackages = [
|
||||
# "aspnetcore-runtime-wrapped-6.0.36"
|
||||
# "aspnetcore-runtime-6.0.36"
|
||||
# "dotnet-sdk-wrapped-6.0.428"
|
||||
# "dotnet-sdk-6.0.428"
|
||||
# ];
|
||||
|
||||
services = {
|
||||
bazarr = {
|
||||
enable = true;
|
||||
group = lib.mkIf config.nmasur.profiles.shared-media.enable "shared";
|
||||
};
|
||||
jellyseerr.enable = true;
|
||||
prowlarr.enable = true;
|
||||
sabnzbd = {
|
||||
enable = true;
|
||||
group = lib.mkIf config.nmasur.profiles.shared-media.enable "shared";
|
||||
# The config file must be editable within the application
|
||||
# It contains server configs and credentials
|
||||
configFile = "/data/downloads/sabnzbd/sabnzbd.ini";
|
||||
};
|
||||
sonarr = {
|
||||
enable = true;
|
||||
group = lib.mkIf config.nmasur.profiles.shared-media.enable "shared";
|
||||
};
|
||||
radarr = {
|
||||
enable = true;
|
||||
group = lib.mkIf config.nmasur.profiles.shared-media.enable "shared";
|
||||
};
|
||||
readarr = {
|
||||
enable = true;
|
||||
group = lib.mkIf config.nmasur.profiles.shared-media.enable "shared";
|
||||
};
|
||||
};
|
||||
|
||||
# Allows shared group to read/write the sabnzbd directory
|
||||
users.users.sabnzbd.homeMode = "0770";
|
||||
|
||||
allowUnfreePackages = [ "unrar" ]; # Required as a dependency for sabnzbd
|
||||
|
||||
# Requires updating the base_url config value in each service
|
||||
# If you try to rewrite the URL, the service won't redirect properly
|
||||
nmasur.presets.services.caddy.routes = [
|
||||
{
|
||||
# Group means that routes with the same name are mutually exclusive,
|
||||
# so they are split between the appropriate services.
|
||||
group = "download";
|
||||
match = [
|
||||
{
|
||||
host = [ hostnames.download ];
|
||||
path = [ "/sonarr*" ];
|
||||
}
|
||||
];
|
||||
handle = [
|
||||
{
|
||||
handler = "reverse_proxy";
|
||||
# We're able to reference the url and port of the service dynamically
|
||||
upstreams = [ { dial = arrConfig.sonarr.url; } ];
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
group = "download";
|
||||
match = [
|
||||
{
|
||||
host = [ hostnames.download ];
|
||||
path = [ "/radarr*" ];
|
||||
}
|
||||
];
|
||||
handle = [
|
||||
{
|
||||
handler = "reverse_proxy";
|
||||
upstreams = [ { dial = arrConfig.radarr.url; } ];
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
group = "download";
|
||||
match = [
|
||||
{
|
||||
host = [ hostnames.download ];
|
||||
path = [ "/readarr*" ];
|
||||
}
|
||||
];
|
||||
handle = [
|
||||
{
|
||||
handler = "reverse_proxy";
|
||||
upstreams = [ { dial = arrConfig.readarr.url; } ];
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
group = "download";
|
||||
match = [
|
||||
{
|
||||
host = [ hostnames.download ];
|
||||
path = [ "/prowlarr*" ];
|
||||
}
|
||||
];
|
||||
handle = [
|
||||
{
|
||||
handler = "reverse_proxy";
|
||||
# Prowlarr doesn't offer a dynamic config, so we have to hardcode it
|
||||
upstreams = [ { dial = "localhost:9696"; } ];
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
group = "download";
|
||||
match = [
|
||||
{
|
||||
host = [ hostnames.download ];
|
||||
path = [ "/bazarr*" ];
|
||||
}
|
||||
];
|
||||
handle = [
|
||||
{
|
||||
handler = "reverse_proxy";
|
||||
upstreams = [
|
||||
{
|
||||
# Bazarr only dynamically sets the port, not the host
|
||||
dial = "localhost:${builtins.toString config.services.bazarr.listenPort}";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
group = "download";
|
||||
match = [
|
||||
{
|
||||
host = [ hostnames.download ];
|
||||
path = [ "/sabnzbd*" ];
|
||||
}
|
||||
];
|
||||
handle = [
|
||||
{
|
||||
handler = "reverse_proxy";
|
||||
upstreams = [ { dial = arrConfig.sabnzbd.url; } ];
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
group = "download";
|
||||
match = [ { host = [ hostnames.download ]; } ];
|
||||
handle = [
|
||||
{
|
||||
handler = "reverse_proxy";
|
||||
upstreams = [ { dial = "localhost:${builtins.toString config.services.jellyseerr.port}"; } ];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
# Configure Cloudflare DNS to point to this machine
|
||||
services.cloudflare-dyndns.domains = [ hostnames.download ];
|
||||
|
||||
# Enable Prometheus exporters
|
||||
systemd.services = lib.mapAttrs' (name: attrs: {
|
||||
name = "prometheus-${name}-exporter";
|
||||
value = {
|
||||
description = "Export Prometheus metrics for ${name}";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "${name}.service" ];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
DynamicUser = true;
|
||||
ExecStart =
|
||||
let
|
||||
# Sabnzbd doesn't accept the URI path, unlike the others
|
||||
url = if name != "sabnzbd" then "http://${attrs.url}/${name}" else "http://${attrs.url}";
|
||||
in
|
||||
# Exportarr is trained to pull from the arr services
|
||||
''
|
||||
${pkgs.exportarr}/bin/exportarr ${name} \
|
||||
--url ${url} \
|
||||
--port ${attrs.exportarrPort}'';
|
||||
EnvironmentFile = lib.mkIf (builtins.hasAttr "apiKey" attrs) attrs.apiKey;
|
||||
Restart = "on-failure";
|
||||
ProtectHome = true;
|
||||
ProtectSystem = "strict";
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
ProtectHostname = true;
|
||||
ProtectClock = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectControlGroups = true;
|
||||
NoNewPrivileges = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
RemoveIPC = true;
|
||||
PrivateMounts = true;
|
||||
};
|
||||
};
|
||||
}) arrConfig;
|
||||
|
||||
# Secrets for Prometheus exporters
|
||||
secrets.radarrApiKey = {
|
||||
source = ./radarr-api-key.age;
|
||||
dest = "/var/private/radarr-api";
|
||||
prefix = "API_KEY=";
|
||||
};
|
||||
secrets.readarrApiKey = {
|
||||
source = ./radarr-api-key.age;
|
||||
dest = "/var/private/readarr-api";
|
||||
prefix = "API_KEY=";
|
||||
};
|
||||
secrets.sonarrApiKey = {
|
||||
source = ./sonarr-api-key.age;
|
||||
dest = "/var/private/sonarr-api";
|
||||
prefix = "API_KEY=";
|
||||
};
|
||||
secrets.prowlarrApiKey = {
|
||||
source = ./prowlarr-api-key.age;
|
||||
dest = "/var/private/prowlarr-api";
|
||||
prefix = "API_KEY=";
|
||||
};
|
||||
secrets.sabnzbdApiKey = {
|
||||
source = ./sabnzbd-api-key.age;
|
||||
dest = "/var/private/sabnzbd-api";
|
||||
prefix = "API_KEY=";
|
||||
};
|
||||
|
||||
# Prometheus scrape targets (expose Exportarr to Prometheus)
|
||||
nmasur.presets.services.prometheus-exporters.scrapeTargets = map (
|
||||
key:
|
||||
"127.0.0.1:${
|
||||
lib.attrsets.getAttrFromPath [
|
||||
key
|
||||
"exportarrPort"
|
||||
] arrConfig
|
||||
}"
|
||||
) (builtins.attrNames arrConfig);
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user