Files
darmanandClaude Sonnet 5 0fa567245a jupiter: GC on every boot, silence mdadm warning, migrate sabnzbd off reused ini
nix.gc (common.nix) is weekly, too slow to catch a switch pinning the old
generation's closure on a 29G eMMC — add a full nix-collect-garbage on every
boot instead. Also set boot.swraid.mdadmConf so eval stops warning that
mdmon will crash (dormant here: the RAID0 array uses native superblocks, so
mdmon never actually runs).

sabnzbd.configFile is deprecated by the module; move to services.sabnzbd.settings
with credentials (web login, api/nzb keys, eweka.nl server) sourced from sops via
secretValues instead of living in a plaintext ini. admin_dir/log_dir are pinned
absolute at their original /mnt/data location so the existing download
queue/history isn't reset by the ini moving to /var/lib/sabnzbd.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 20:58:40 +02:00

109 lines
5.5 KiB
Nix

{ config, ... }:
# SABnzbd — usenet downloader. Migrated off a reused hand-authored ini
# (servers/API key/history originally imported from the old ZimaOS docker
# stack) onto NixOS-managed `settings`, per the module's own deprecation
# notice for `configFile`. Only the values that differ from SABnzbd's own
# built-in defaults are declared here — everything else falls back to the
# same defaults SABnzbd was already using.
#
# `admin_dir`/`log_dir` MUST stay absolute: the module writes the merged ini
# to /var/lib/sabnzbd/sabnzbd.ini (eMMC), and both dirs are otherwise
# relative to wherever the ini lives. Pointing them back at the ORIGINAL
# /mnt/data location keeps the existing download queue/history database
# (admin_dir) intact — a relative default here would silently "reset"
# SABnzbd to an empty queue on first switch, even though nothing was deleted.
{
services.sabnzbd = {
enable = true;
allowConfigWrite = true; # let sabnzbd keep saving state (queue, wizard flags, ...)
settings = {
misc = {
host = "::";
port = 8085;
web_color = "Night";
enable_https = false;
url_base = "/sabnzbd";
cache_limit = "1G";
download_dir = "/mnt/data/HighSeas/Downloads/Incomplete";
complete_dir = "/mnt/data/HighSeas/Downloads";
admin_dir = "/mnt/data/AppData/sabnzbd/config/admin";
log_dir = "/mnt/data/AppData/sabnzbd/config/logs";
# Verbatim from the migrated ini — includes a pre-existing "izma ace"
# (missing comma) left as-is rather than silently "fixed" here.
unwanted_extensions = "exe, com, bat, ink, js, vbs, ps1, sh, py, php, pl, rb, jar, class, swf, scr, hta, msi, msp, msu, pif, ink, chm, vb, vba, ws, wsf, wsh, xll, docm, dotm, xlsm, xltm, pptm, potm, ppsm, sldm, thmx, xlam, ppam, docb, dotb, xltb, mht, mhtml, url, iqylink, deamon, elf, dmg, iso, cue, nrg, img, udf, wim, vhd, vhdx, vmdk, ova, tf, pb, savedmodel, h5, ckpt, meta, index, data-00000-of-00001, vocab, config, model, pt, tgz, tar.gz, bz2, xz, izma ace, arc, cab, jar, izh, pea, sit, sitx, sqx, zoo, pak, upk, bsa, dat, nzb, nzbs, nzb.gz, nzb.bz2";
host_whitelist = "cd1a98d07ece, helium, sabnzbd.jupiter.sol, localhost, jupiter, jupiter.sol";
username = "@sabnzbd_web_username@";
password = "@sabnzbd_web_password@";
api_key = "@sabnzbd_api_key@";
nzb_key = "@sabnzbd_nzb_key@";
};
servers."news.eweka.nl" = {
name = "news.eweka.nl";
displayname = "news.eweka.nl";
host = "news.eweka.nl";
port = 563;
connections = 8;
ssl = true;
ssl_verify = "strict";
username = "@sabnzbd_eweka_username@";
password = "@sabnzbd_eweka_password@";
};
categories = {
"*" = { name = "*"; order = 0; pp = 3; };
movies = { name = "movies"; order = 1; script = "Default"; priority = -100; };
tv = { name = "tv"; order = 2; script = "Default"; priority = -100; };
audio = { name = "audio"; order = 3; script = "Default"; priority = -100; };
software = { name = "software"; order = 4; script = "Default"; priority = -100; };
prowlarr = { name = "prowlarr"; order = 5; script = "Default"; priority = -100; };
xxx = { name = "xxx"; order = 6; script = "Default"; priority = -100; };
readarr = { name = "readarr"; order = 7; script = "Default"; priority = -100; };
};
};
secretValues = {
"@sabnzbd_web_username@" = config.sops.secrets.sabnzbd_web_username.path;
"@sabnzbd_web_password@" = config.sops.secrets.sabnzbd_web_password.path;
"@sabnzbd_api_key@" = config.sops.secrets.sabnzbd_api_key.path;
"@sabnzbd_nzb_key@" = config.sops.secrets.sabnzbd_nzb_key.path;
"@sabnzbd_eweka_username@" = config.sops.secrets.sabnzbd_eweka_username.path;
"@sabnzbd_eweka_password@" = config.sops.secrets.sabnzbd_eweka_password.path;
};
};
# Write access to the shared downloads dir (owned darman:users on disk).
users.users.sabnzbd.extraGroups = [ "users" ];
# download/complete/admin dirs all live on the array, but systemd only
# derives RequiresMountsFor from /var/lib/sabnzbd (eMMC) — so with the array
# absent sabnzbd would start and download onto the 29G OS disk.
systemd.services.sabnzbd.unitConfig.RequiresMountsFor = [ "/mnt/data" ];
systemd.services.fix-downloads-perms.unitConfig.RequiresMountsFor = [ "/mnt/data" ];
# SABnzbd hardcodes completed job folders to 0700 on every job, ignoring
# the ini's `umask` (that only covers files during unpack, not the job
# dir itself). setgid on Downloads keeps the group as "users" but perm
# bits still come back zeroed, locking out cinephage/mediamanager — sweep
# it clean instead of fighting SABnzbd.
systemd.services.fix-downloads-perms = {
description = "Fix group perms SABnzbd resets on completed downloads";
serviceConfig.Type = "oneshot";
script = ''
find /mnt/data/HighSeas/Downloads \
! -group users -exec chgrp users {} + 2>/dev/null || true
find /mnt/data/HighSeas/Downloads -type d ! -perm -g+rwx \
-exec chmod g+rwx {} + 2>/dev/null || true
find /mnt/data/HighSeas/Downloads -type f ! -perm -g+rw \
-exec chmod g+rw {} + 2>/dev/null || true
'';
};
systemd.timers.fix-downloads-perms = {
description = "Periodically fix group perms under HighSeas/Downloads";
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "1m";
OnUnitActiveSec = "2m";
};
};
}