From 4502e197bfbb63d1c5d7a0ab1d4cb0773db9c933 Mon Sep 17 00:00:00 2001 From: wi11-holdsworth <83637728+wi11-holdsworth@users.noreply.github.com> Date: Mon, 29 Dec 2025 14:00:36 +1100 Subject: [PATCH 1/6] refactor: store port as integer --- modules/nixos/features/copyparty.nix | 7 +++---- modules/nixos/features/couchdb.nix | 10 +++------- modules/nixos/features/flaresolverr.nix | 10 +++------- modules/nixos/features/homepage-dashboard.nix | 6 +++--- modules/nixos/features/immich.nix | 10 +++------- modules/nixos/features/jellyfin.nix | 4 ++-- modules/nixos/features/karakeep.nix | 6 +++--- modules/nixos/features/lidarr.nix | 12 +++++------- modules/nixos/features/miniflux.nix | 6 +++--- modules/nixos/features/ntfy-sh.nix | 6 +++--- modules/nixos/features/paperless.nix | 7 +++---- modules/nixos/features/prowlarr.nix | 15 +++++---------- modules/nixos/features/qbittorrent.nix | 10 +++------- modules/nixos/features/radarr.nix | 12 +++++------- modules/nixos/features/radicale.nix | 8 ++++---- modules/nixos/features/sonarr.nix | 12 +++++------- modules/nixos/features/syncthing.nix | 6 +++--- modules/nixos/features/vaultwarden.nix | 6 +++--- modules/templates/web-feature.nix | 4 ++-- 19 files changed, 64 insertions(+), 93 deletions(-) diff --git a/modules/nixos/features/copyparty.nix b/modules/nixos/features/copyparty.nix index a3b8114..560df1e 100644 --- a/modules/nixos/features/copyparty.nix +++ b/modules/nixos/features/copyparty.nix @@ -2,12 +2,11 @@ # keep-sorted start config, inputs, - lib, # keep-sorted end ... }: let - port = "5000"; + port = 5000; in { imports = [ inputs.copyparty.nixosModules.default ]; @@ -20,7 +19,7 @@ in e2dsa = true; e2ts = true; e2vu = true; - p = lib.toInt port; + p = port; }; accounts.will.passwordFile = config.age.secrets.copyparty-will.path; @@ -37,7 +36,7 @@ in nginx.virtualHosts."copyparty.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; diff --git a/modules/nixos/features/couchdb.nix b/modules/nixos/features/couchdb.nix index 5b24367..d7656ee 100644 --- a/modules/nixos/features/couchdb.nix +++ b/modules/nixos/features/couchdb.nix @@ -1,9 +1,5 @@ -{ - lib, - ... -}: let - port = "5984"; + port = 5984; in { services = { @@ -12,7 +8,7 @@ in databaseDir = "/srv/couchdb"; viewIndexDir = "/srv/couchdb"; configFile = "/srv/couchdb"; - port = lib.toInt port; + inherit port; extraConfig = { chttpd = { require_valid_user = true; @@ -41,7 +37,7 @@ in nginx.virtualHosts."couchdb.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; } diff --git a/modules/nixos/features/flaresolverr.nix b/modules/nixos/features/flaresolverr.nix index 86afdcd..e9f7f45 100644 --- a/modules/nixos/features/flaresolverr.nix +++ b/modules/nixos/features/flaresolverr.nix @@ -1,21 +1,17 @@ -{ - lib, - ... -}: let - port = "5011"; + port = 5011; in { services = { flaresolverr = { enable = true; - port = lib.toInt port; + inherit port; }; nginx.virtualHosts."flaresolverr.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; } diff --git a/modules/nixos/features/homepage-dashboard.nix b/modules/nixos/features/homepage-dashboard.nix index c1eb3d1..df30830 100644 --- a/modules/nixos/features/homepage-dashboard.nix +++ b/modules/nixos/features/homepage-dashboard.nix @@ -7,7 +7,7 @@ ... }: let - port = "5004"; + port = 5004; genSecrets = secrets: lib.genAttrs secrets (secret: { @@ -38,7 +38,7 @@ in services = { homepage-dashboard = { enable = true; - listenPort = lib.toInt port; + listenPort = port; allowedHosts = "homepage-dashboard.fi33.buzz"; services = [ # keep-sorted start block=yes @@ -300,7 +300,7 @@ in nginx.virtualHosts."homepage-dashboard.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; diff --git a/modules/nixos/features/immich.nix b/modules/nixos/features/immich.nix index 3d83d33..6a0abd4 100644 --- a/modules/nixos/features/immich.nix +++ b/modules/nixos/features/immich.nix @@ -1,15 +1,11 @@ -{ - lib, - ... -}: let - port = "2283"; + port = 2283; in { services = { immich = { enable = true; - port = lib.toInt "${port}"; + inherit port; mediaLocation = "/srv/immich"; }; @@ -28,7 +24,7 @@ in forceSSL = true; useACMEHost = "fi33.buzz"; locations."/" = { - proxyPass = "http://[::1]:${port}"; + proxyPass = "http://[::1]:${toString port}"; proxyWebsockets = true; }; }; diff --git a/modules/nixos/features/jellyfin.nix b/modules/nixos/features/jellyfin.nix index e64f6ad..330adff 100644 --- a/modules/nixos/features/jellyfin.nix +++ b/modules/nixos/features/jellyfin.nix @@ -1,5 +1,5 @@ let - port = "8096"; + port = 8096; in { services = { @@ -12,7 +12,7 @@ in nginx.virtualHosts."jellyfin.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; diff --git a/modules/nixos/features/karakeep.nix b/modules/nixos/features/karakeep.nix index c113f66..09f8163 100644 --- a/modules/nixos/features/karakeep.nix +++ b/modules/nixos/features/karakeep.nix @@ -1,12 +1,12 @@ let - port = "5014"; + port = 5014; in { services = { karakeep = { enable = true; extraEnvironment = { - PORT = port; + PORT = toString port; DISABLE_NEW_RELEASE_CHECK = "true"; }; }; @@ -14,7 +14,7 @@ in nginx.virtualHosts."karakeep.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; } diff --git a/modules/nixos/features/lidarr.nix b/modules/nixos/features/lidarr.nix index 39e6253..8132318 100644 --- a/modules/nixos/features/lidarr.nix +++ b/modules/nixos/features/lidarr.nix @@ -1,23 +1,21 @@ -{ - lib, - ... -}: let - port = "5012"; + port = 5012; in { services = { lidarr = { enable = true; dataDir = "/srv/lidarr"; - settings.server.port = lib.toInt port; + settings.server = { + inherit port; + }; group = "media"; }; nginx.virtualHosts."lidarr.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; } diff --git a/modules/nixos/features/miniflux.nix b/modules/nixos/features/miniflux.nix index 7fd7403..10c4eeb 100644 --- a/modules/nixos/features/miniflux.nix +++ b/modules/nixos/features/miniflux.nix @@ -3,7 +3,7 @@ ... }: let - port = "5010"; + port = 5010; in { services = { @@ -12,7 +12,7 @@ in adminCredentialsFile = config.age.secrets.miniflux-creds.path; config = { BASE_URL = "https://miniflux.fi33.buzz"; - LISTEN_ADDR = "localhost:${port}"; + LISTEN_ADDR = "localhost:${toString port}"; }; }; @@ -28,7 +28,7 @@ in nginx.virtualHosts."miniflux.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; diff --git a/modules/nixos/features/ntfy-sh.nix b/modules/nixos/features/ntfy-sh.nix index 681047f..d5a70e8 100644 --- a/modules/nixos/features/ntfy-sh.nix +++ b/modules/nixos/features/ntfy-sh.nix @@ -1,5 +1,5 @@ let - port = "5002"; + port = 5002; in { services = { @@ -7,7 +7,7 @@ in enable = true; settings = { base-url = "https://ntfy-sh.fi33.buzz"; - listen-http = ":${port}"; + listen-http = ":${toString port}"; behind-proxy = true; }; }; @@ -16,7 +16,7 @@ in forceSSL = true; useACMEHost = "fi33.buzz"; locations."/" = { - proxyPass = "http://localhost:${port}"; + proxyPass = "http://localhost:${toString port}"; proxyWebsockets = true; }; }; diff --git a/modules/nixos/features/paperless.nix b/modules/nixos/features/paperless.nix index 348b42d..6b61e35 100644 --- a/modules/nixos/features/paperless.nix +++ b/modules/nixos/features/paperless.nix @@ -1,10 +1,9 @@ { config, - lib, ... }: let - port = "5013"; + port = 5013; in { services = { @@ -13,7 +12,7 @@ in dataDir = "/srv/paperless"; database.createLocally = true; passwordFile = config.age.secrets.paperless.path; - port = lib.toInt port; + inherit port; settings = { PAPERLESS_URL = "https://paperless.fi33.buzz"; }; @@ -33,7 +32,7 @@ in nginx.virtualHosts."paperless.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; diff --git a/modules/nixos/features/prowlarr.nix b/modules/nixos/features/prowlarr.nix index 2e439b5..9fbb8e6 100644 --- a/modules/nixos/features/prowlarr.nix +++ b/modules/nixos/features/prowlarr.nix @@ -1,26 +1,21 @@ -{ - lib, - ... -}: let - port = "5009"; + port = 5009; in { services = { prowlarr = { enable = true; dataDir = "/srv/prowlarr"; - settings.server.port = lib.toInt port; + settings.server = { + inherit port; + }; }; nginx = { virtualHosts."prowlarr.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/" = { - proxyPass = "http://localhost:${port}"; - # proxyWebsockets = true; - }; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; }; diff --git a/modules/nixos/features/qbittorrent.nix b/modules/nixos/features/qbittorrent.nix index b67b01e..0134eb1 100644 --- a/modules/nixos/features/qbittorrent.nix +++ b/modules/nixos/features/qbittorrent.nix @@ -1,15 +1,11 @@ -{ - lib, - ... -}: let - port = "5005"; + port = 5005; in { services = { qbittorrent = { enable = true; - webuiPort = lib.toInt port; + webuiPort = port; profileDir = "/srv"; group = "media"; extraArgs = [ @@ -20,7 +16,7 @@ in nginx.virtualHosts."qbittorrent.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; diff --git a/modules/nixos/features/radarr.nix b/modules/nixos/features/radarr.nix index 51aeef1..8cce599 100644 --- a/modules/nixos/features/radarr.nix +++ b/modules/nixos/features/radarr.nix @@ -1,23 +1,21 @@ -{ - lib, - ... -}: let - port = "5007"; + port = 5007; in { services = { radarr = { enable = true; dataDir = "/srv/radarr"; - settings.server.port = lib.toInt port; + settings.server = { + inherit port; + }; group = "media"; }; nginx.virtualHosts."radarr.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; } diff --git a/modules/nixos/features/radicale.nix b/modules/nixos/features/radicale.nix index 1e0b722..6ced520 100644 --- a/modules/nixos/features/radicale.nix +++ b/modules/nixos/features/radicale.nix @@ -3,7 +3,7 @@ ... }: let - port = "5003"; + port = 5003; in { services = { @@ -12,8 +12,8 @@ in settings = { server = { hosts = [ - "0.0.0.0:${port}" - "[::]:${port}" + "0.0.0.0:${toString port}" + "[::]:${toString port}" ]; }; auth = { @@ -30,7 +30,7 @@ in nginx.virtualHosts."radicale.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; diff --git a/modules/nixos/features/sonarr.nix b/modules/nixos/features/sonarr.nix index 95ac80e..f5ff5b3 100644 --- a/modules/nixos/features/sonarr.nix +++ b/modules/nixos/features/sonarr.nix @@ -1,23 +1,21 @@ -{ - lib, - ... -}: let - port = "5006"; + port = 5006; in { services = { sonarr = { enable = true; dataDir = "/srv/sonarr"; - settings.server.port = lib.toInt port; + settings.server = { + inherit port; + }; group = "media"; }; nginx.virtualHosts."sonarr.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; } diff --git a/modules/nixos/features/syncthing.nix b/modules/nixos/features/syncthing.nix index 47e804c..513b467 100644 --- a/modules/nixos/features/syncthing.nix +++ b/modules/nixos/features/syncthing.nix @@ -4,7 +4,7 @@ ... }: let - port = "5008"; + port = 5008; devicesList = [ # keep-sorted start block=yes { @@ -45,7 +45,7 @@ in services = { syncthing = { enable = true; - guiAddress = "0.0.0.0:${port}"; + guiAddress = "0.0.0.0:${toString port}"; openDefaultPorts = true; user = "${userName}"; dataDir = "/home/${userName}"; @@ -69,7 +69,7 @@ in nginx.virtualHosts."syncthing.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; } diff --git a/modules/nixos/features/vaultwarden.nix b/modules/nixos/features/vaultwarden.nix index c4e069d..2ffb556 100644 --- a/modules/nixos/features/vaultwarden.nix +++ b/modules/nixos/features/vaultwarden.nix @@ -3,7 +3,7 @@ ... }: let - port = "5001"; + port = 5001; in { services = { @@ -11,7 +11,7 @@ in enable = true; backupDir = "/srv/vaultwarden"; config = { - rocketPort = "${port}"; + rocketPort = toString port; domain = "https://vaultwarden.fi33.buzz"; signupsAllowed = false; invitationsAllowed = false; @@ -26,7 +26,7 @@ in forceSSL = true; useACMEHost = "fi33.buzz"; locations."/" = { - proxyPass = "http://localhost:${port}"; + proxyPass = "http://localhost:${toString port}"; proxyWebsockets = true; }; }; diff --git a/modules/templates/web-feature.nix b/modules/templates/web-feature.nix index 98eba78..ab1b9f0 100644 --- a/modules/templates/web-feature.nix +++ b/modules/templates/web-feature.nix @@ -1,5 +1,5 @@ let - port = "port"; + port = 0000; in { services = { @@ -12,7 +12,7 @@ in nginx.virtualHosts."feature.fi33.buzz" = { forceSSL = true; useACMEHost = "fi33.buzz"; - locations."/".proxyPass = "http://localhost:${port}"; + locations."/".proxyPass = "http://localhost:${toString port}"; }; }; } From 6130f543b933164a10bbb083b1fc1697782d5758 Mon Sep 17 00:00:00 2001 From: wi11-holdsworth <83637728+wi11-holdsworth@users.noreply.github.com> Date: Mon, 29 Dec 2025 14:08:20 +1100 Subject: [PATCH 2/6] fix: web-feature template now includes a more fleshed-out backup section --- modules/templates/web-feature.nix | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/templates/web-feature.nix b/modules/templates/web-feature.nix index ab1b9f0..6240e4e 100644 --- a/modules/templates/web-feature.nix +++ b/modules/templates/web-feature.nix @@ -7,7 +7,17 @@ in enable = true; }; - borgbackup.jobs = feature { }; + # borgmatic.settings = { + # source_directories = [ ]; + # postgresql_databases = [ + # { + # name = "feature"; + # hostname = "localhost"; + # username = "root"; + # password = "{credential systemd borgmatic-pg}"; + # } + # ]; + # }; nginx.virtualHosts."feature.fi33.buzz" = { forceSSL = true; From b5c3d6419cada5f6008f68f40378e74ea895d4a5 Mon Sep 17 00:00:00 2001 From: wi11-holdsworth <83637728+wi11-holdsworth@users.noreply.github.com> Date: Mon, 29 Dec 2025 15:26:32 +1100 Subject: [PATCH 3/6] feat: re-order services on homepage dashboard --- modules/nixos/features/homepage-dashboard.nix | 274 +++++++++--------- 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/modules/nixos/features/homepage-dashboard.nix b/modules/nixos/features/homepage-dashboard.nix index df30830..b4b7897 100644 --- a/modules/nixos/features/homepage-dashboard.nix +++ b/modules/nixos/features/homepage-dashboard.nix @@ -43,7 +43,134 @@ in services = [ # keep-sorted start block=yes { - "Cloud Services" = [ + "Media Management" = [ + { + "Immich" = { + "description" = "Photo backup"; + "icon" = "immich.svg"; + "href" = "https://immich.fi33.buzz/"; + "widget" = { + "type" = "immich"; + "fields" = [ + "users" + "photos" + "videos" + "storage" + ]; + "url" = "https://immich.fi33.buzz/"; + "version" = 2; + "key" = "@immich@"; + }; + }; + } + { + "Miniflux" = { + "description" = "RSS aggregator"; + "icon" = "miniflux.svg"; + "href" = "https://miniflux.fi33.buzz/"; + "widget" = { + "type" = "miniflux"; + "url" = "https://miniflux.fi33.buzz/"; + "key" = "@miniflux@"; + }; + }; + } + { + "Paperless" = { + "description" = "Digital filing cabinet"; + "icon" = "paperless.svg"; + "href" = "https://paperless.fi33.buzz/"; + "widget" = { + "type" = "paperlessngx"; + "url" = "https://paperless.fi33.buzz/"; + "username" = "admin"; + "password" = "@paperless@"; + }; + }; + } + ]; + } + { + "Media Streaming" = [ + { + "Jellyfin" = { + "description" = "Media streaming"; + "icon" = "jellyfin.svg"; + "href" = "https://jellyfin.fi33.buzz/"; + "widget" = { + "type" = "jellyfin"; + "url" = "https://jellyfin.fi33.buzz/"; + "key" = "@jellyfin@"; + "enableBlocks" = true; + "enableNowPlaying" = true; + "enableUser" = true; + "showEpisodeNumber" = true; + "expandOneStreamToTwoRows" = false; + }; + }; + } + { + "Radarr" = { + "description" = "Movie collection manager"; + "icon" = "radarr.svg"; + "href" = "https://radarr.fi33.buzz/"; + "widget" = { + "type" = "radarr"; + "url" = "https://radarr.fi33.buzz/"; + "key" = "@radarr@"; + "enableQueue" = true; + }; + }; + } + { + "Sonarr" = { + "description" = "TV show collection manager"; + "icon" = "sonarr.svg"; + "href" = "https://sonarr.fi33.buzz/"; + "widget" = { + "type" = "sonarr"; + "url" = "https://sonarr.fi33.buzz/"; + "key" = "@sonarr@"; + "enableQueue" = true; + }; + }; + } + { + "Lidarr" = { + "description" = "Music collection manager"; + "icon" = "lidarr.svg"; + "href" = "https://lidarr.fi33.buzz/"; + "widget" = { + "type" = "lidarr"; + "url" = "https://lidarr.fi33.buzz/"; + "key" = "@lidarr@"; + "enableQueue" = true; + }; + }; + } + { + "Prowlarr" = { + "description" = "Indexer management tool"; + "icon" = "prowlarr.svg"; + "href" = "https://prowlarr.fi33.buzz/"; + "widget" = { + "type" = "prowlarr"; + "url" = "https://prowlarr.fi33.buzz/"; + "key" = "@prowlarr@"; + }; + }; + } + { + "qBittorrent" = { + "description" = "BitTorrent client"; + "icon" = "qbittorrent.svg"; + "href" = "https://qbittorrent.fi33.buzz/"; + }; + } + ]; + } + { + "Services" = [ { "copyparty" = { "description" = "Cloud file manager"; @@ -79,13 +206,6 @@ in "href" = "https://syncthing.fi33.buzz/"; }; } - { - "qBittorrent" = { - "description" = "BitTorrent client"; - "icon" = "qbittorrent.svg"; - "href" = "https://qbittorrent.fi33.buzz/"; - }; - } { "Vaultwarden" = { "description" = "Password manager"; @@ -95,126 +215,6 @@ in } ]; } - { - "Media Management" = [ - { - "Lidarr" = { - "description" = "Music collection manager"; - "icon" = "lidarr.svg"; - "href" = "https://lidarr.fi33.buzz/"; - "widget" = { - "type" = "lidarr"; - "url" = "https://lidarr.fi33.buzz/"; - "key" = "@lidarr@"; - "enableQueue" = true; - }; - }; - } - { - "Prowlarr" = { - "description" = "Indexer management tool"; - "icon" = "prowlarr.svg"; - "href" = "https://prowlarr.fi33.buzz/"; - "widget" = { - "type" = "prowlarr"; - "url" = "https://prowlarr.fi33.buzz/"; - "key" = "@prowlarr@"; - }; - }; - } - { - "Radarr" = { - "description" = "Movie collection manager"; - "icon" = "radarr.svg"; - "href" = "https://radarr.fi33.buzz/"; - "widget" = { - "type" = "radarr"; - "url" = "https://radarr.fi33.buzz/"; - "key" = "@radarr@"; - "enableQueue" = true; - }; - }; - } - { - "Sonarr" = { - "description" = "TV show collection manager"; - "icon" = "sonarr.svg"; - "href" = "https://sonarr.fi33.buzz/"; - "widget" = { - "type" = "sonarr"; - "url" = "https://sonarr.fi33.buzz/"; - "key" = "@sonarr@"; - "enableQueue" = true; - }; - }; - } - ]; - } - { - "Media Streaming" = [ - { - "Immich" = { - "description" = "Photo backup"; - "icon" = "immich.svg"; - "href" = "https://immich.fi33.buzz/"; - "widget" = { - "type" = "immich"; - "fields" = [ - "users" - "photos" - "videos" - "storage" - ]; - "url" = "https://immich.fi33.buzz/"; - "version" = 2; - "key" = "@immich@"; - }; - }; - } - { - "Jellyfin" = { - "description" = "Media streaming"; - "icon" = "jellyfin.svg"; - "href" = "https://jellyfin.fi33.buzz/"; - "widget" = { - "type" = "jellyfin"; - "url" = "https://jellyfin.fi33.buzz/"; - "key" = "@jellyfin@"; - "enableBlocks" = true; - "enableNowPlaying" = true; - "enableUser" = true; - "showEpisodeNumber" = true; - "expandOneStreamToTwoRows" = false; - }; - }; - } - { - "Miniflux" = { - "description" = "RSS aggregator"; - "icon" = "miniflux.svg"; - "href" = "https://miniflux.fi33.buzz/"; - "widget" = { - "type" = "miniflux"; - "url" = "https://miniflux.fi33.buzz/"; - "key" = "@miniflux@"; - }; - }; - } - { - "Paperless" = { - "description" = "Digital filing cabinet"; - "icon" = "paperless.svg"; - "href" = "https://paperless.fi33.buzz/"; - "widget" = { - "type" = "paperlessngx"; - "url" = "https://paperless.fi33.buzz/"; - "username" = "admin"; - "password" = "@paperless@"; - }; - }; - } - ]; - } { "Utilities" = [ { @@ -234,22 +234,22 @@ in color = "neutral"; headerStyle = "clean"; layout = [ - { - "Media Streaming" = { - style = "row"; - columns = 4; - useEqualHeights = true; - }; - } { "Media Management" = { style = "row"; - columns = 4; + columns = 3; useEqualHeights = true; }; } { - "Cloud Services" = { + "Media Streaming" = { + style = "row"; + columns = 3; + useEqualHeights = true; + }; + } + { + "Services" = { style = "row"; columns = 3; }; From 7af587d54655fdc52e312ab790439d0a2b390473 Mon Sep 17 00:00:00 2001 From: wi11-holdsworth <83637728+wi11-holdsworth@users.noreply.github.com> Date: Mon, 29 Dec 2025 16:37:00 +1100 Subject: [PATCH 4/6] feat: install readarr --- modules/nixos/bundles/server.nix | 2 +- modules/nixos/features/homepage-dashboard.nix | 160 ++++++++++-------- modules/nixos/features/readarr.nix | 33 ++++ secrets/readarr.age | 10 ++ secrets/secrets.nix | 1 + 5 files changed, 131 insertions(+), 75 deletions(-) create mode 100644 modules/nixos/features/readarr.nix create mode 100644 secrets/readarr.age diff --git a/modules/nixos/bundles/server.nix b/modules/nixos/bundles/server.nix index c4ea292..210735e 100644 --- a/modules/nixos/bundles/server.nix +++ b/modules/nixos/bundles/server.nix @@ -14,7 +14,6 @@ "karakeep" "lidarr" "miniflux" - "radicale" "nginx" "ntfy-sh" "paperless" @@ -22,6 +21,7 @@ "qbittorrent" "radarr" "radicale" + "readarr" "sonarr" "syncthing" "vaultwarden" diff --git a/modules/nixos/features/homepage-dashboard.nix b/modules/nixos/features/homepage-dashboard.nix index b4b7897..42a4f2a 100644 --- a/modules/nixos/features/homepage-dashboard.nix +++ b/modules/nixos/features/homepage-dashboard.nix @@ -30,6 +30,7 @@ let "paperless" "prowlarr" "radarr" + "readarr" "sonarr" # keep-sorted end ]; @@ -41,74 +42,8 @@ in listenPort = port; allowedHosts = "homepage-dashboard.fi33.buzz"; services = [ - # keep-sorted start block=yes { "Media Management" = [ - { - "Immich" = { - "description" = "Photo backup"; - "icon" = "immich.svg"; - "href" = "https://immich.fi33.buzz/"; - "widget" = { - "type" = "immich"; - "fields" = [ - "users" - "photos" - "videos" - "storage" - ]; - "url" = "https://immich.fi33.buzz/"; - "version" = 2; - "key" = "@immich@"; - }; - }; - } - { - "Miniflux" = { - "description" = "RSS aggregator"; - "icon" = "miniflux.svg"; - "href" = "https://miniflux.fi33.buzz/"; - "widget" = { - "type" = "miniflux"; - "url" = "https://miniflux.fi33.buzz/"; - "key" = "@miniflux@"; - }; - }; - } - { - "Paperless" = { - "description" = "Digital filing cabinet"; - "icon" = "paperless.svg"; - "href" = "https://paperless.fi33.buzz/"; - "widget" = { - "type" = "paperlessngx"; - "url" = "https://paperless.fi33.buzz/"; - "username" = "admin"; - "password" = "@paperless@"; - }; - }; - } - ]; - } - { - "Media Streaming" = [ - { - "Jellyfin" = { - "description" = "Media streaming"; - "icon" = "jellyfin.svg"; - "href" = "https://jellyfin.fi33.buzz/"; - "widget" = { - "type" = "jellyfin"; - "url" = "https://jellyfin.fi33.buzz/"; - "key" = "@jellyfin@"; - "enableBlocks" = true; - "enableNowPlaying" = true; - "enableUser" = true; - "showEpisodeNumber" = true; - "expandOneStreamToTwoRows" = false; - }; - }; - } { "Radarr" = { "description" = "Movie collection manager"; @@ -148,6 +83,19 @@ in }; }; } + { + "Readarr" = { + "description" = "Book collection manager"; + "icon" = "readarr.svg"; + "href" = "https://readarr.fi33.buzz/"; + "widget" = { + "type" = "readarr"; + "url" = "https://readarr.fi33.buzz/"; + "key" = "@readarr@"; + "enableQueue" = true; + }; + }; + } { "Prowlarr" = { "description" = "Indexer management tool"; @@ -169,6 +117,71 @@ in } ]; } + { + "Media Streaming" = [ + { + "Immich" = { + "description" = "Photo backup"; + "icon" = "immich.svg"; + "href" = "https://immich.fi33.buzz/"; + "widget" = { + "type" = "immich"; + "fields" = [ + "users" + "photos" + "videos" + "storage" + ]; + "url" = "https://immich.fi33.buzz/"; + "version" = 2; + "key" = "@immich@"; + }; + }; + } + { + "Jellyfin" = { + "description" = "Media streaming"; + "icon" = "jellyfin.svg"; + "href" = "https://jellyfin.fi33.buzz/"; + "widget" = { + "type" = "jellyfin"; + "url" = "https://jellyfin.fi33.buzz/"; + "key" = "@jellyfin@"; + "enableBlocks" = true; + "enableNowPlaying" = true; + "enableUser" = true; + "showEpisodeNumber" = true; + "expandOneStreamToTwoRows" = false; + }; + }; + } + { + "Miniflux" = { + "description" = "RSS aggregator"; + "icon" = "miniflux.svg"; + "href" = "https://miniflux.fi33.buzz/"; + "widget" = { + "type" = "miniflux"; + "url" = "https://miniflux.fi33.buzz/"; + "key" = "@miniflux@"; + }; + }; + } + { + "Paperless" = { + "description" = "Digital filing cabinet"; + "icon" = "paperless.svg"; + "href" = "https://paperless.fi33.buzz/"; + "widget" = { + "type" = "paperlessngx"; + "url" = "https://paperless.fi33.buzz/"; + "username" = "admin"; + "password" = "@paperless@"; + }; + }; + } + ]; + } { "Services" = [ { @@ -226,7 +239,6 @@ in } ]; } - # keep-sorted end ]; settings = { title = "Mission Control"; @@ -234,13 +246,6 @@ in color = "neutral"; headerStyle = "clean"; layout = [ - { - "Media Management" = { - style = "row"; - columns = 3; - useEqualHeights = true; - }; - } { "Media Streaming" = { style = "row"; @@ -254,6 +259,13 @@ in columns = 3; }; } + { + "Media Management" = { + style = "row"; + columns = 3; + useEqualHeights = true; + }; + } { "Utilities" = { style = "row"; diff --git a/modules/nixos/features/readarr.nix b/modules/nixos/features/readarr.nix new file mode 100644 index 0000000..f0f3227 --- /dev/null +++ b/modules/nixos/features/readarr.nix @@ -0,0 +1,33 @@ +let + port = 5016; +in +{ + services = { + readarr = { + enable = true; + dataDir = "/srv/readarr"; + settings.server = { + inherit port; + }; + group = "media"; + }; + + # borgmatic.settings = { + # source_directories = [ ]; + # postgresql_databases = [ + # { + # name = "readarr"; + # hostname = "localhost"; + # username = "root"; + # password = "{credential systemd borgmatic-pg}"; + # } + # ]; + # }; + + nginx.virtualHosts."readarr.fi33.buzz" = { + forceSSL = true; + useACMEHost = "fi33.buzz"; + locations."/".proxyPass = "http://localhost:${toString port}"; + }; + }; +} diff --git a/secrets/readarr.age b/secrets/readarr.age new file mode 100644 index 0000000..e0d0607 --- /dev/null +++ b/secrets/readarr.age @@ -0,0 +1,10 @@ +age-encryption.org/v1 +-> ssh-ed25519 qLT+DQ qeJ25W5TGvWY8xc1I5sjjtP/98nGqoRMIFk6xLIbmi8 +RhUcEjz6mFp6uNVOpOgg6fPyL2cyrZH1ZWJTrax2xOE +-> ssh-ed25519 7+xRyQ jhJX/0+ZO+teoM2rUmdyFuI9V+tMe5kQaaHQFxwBGSU +fJmXSc/c3lth0cQgx8p/7G0WrnfgioSs8OcRa56B2s0 +-> ssh-ed25519 LtK9yQ UH9T6lRLG0pi0P84B9Zs/22nCKAoOAwL6KAmj+536U4 +h2DEqoPLgFqmVZOk/RhAIuifCexqt3ZFsIsCDm5KI3M +--- 6FY4tnGR8EIQyCWc3Xa3t8EqwcynoORmZqsp9zWUzZM +nā]Z0rTi:EE!  +uB{4cfvޟKj^2/` \ No newline at end of file diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 69b1be1..74ef3d4 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -30,6 +30,7 @@ in "prowlarr.age".publicKeys = users; "radarr.age".publicKeys = users; "radicale.age".publicKeys = users; + "readarr.age".publicKeys = users; "sonarr.age".publicKeys = users; "vaultwarden-admin.age".publicKeys = users; # keep-sorted end From 3d2a47ec7931c761a87701b194a081965ac2a73e Mon Sep 17 00:00:00 2001 From: wi11-holdsworth <83637728+wi11-holdsworth@users.noreply.github.com> Date: Mon, 29 Dec 2025 13:55:36 +1100 Subject: [PATCH 5/6] feat: install kavita --- modules/nixos/bundles/server.nix | 1 + modules/nixos/features/kavita.nix | 25 +++++++++++++++++++++++++ secrets/kavita.age | Bin 0 -> 521 bytes secrets/secrets.nix | 1 + 4 files changed, 27 insertions(+) create mode 100644 modules/nixos/features/kavita.nix create mode 100644 secrets/kavita.age diff --git a/modules/nixos/bundles/server.nix b/modules/nixos/bundles/server.nix index 210735e..a084543 100644 --- a/modules/nixos/bundles/server.nix +++ b/modules/nixos/bundles/server.nix @@ -12,6 +12,7 @@ "immich" "jellyfin" "karakeep" + "kavita" "lidarr" "miniflux" "nginx" diff --git a/modules/nixos/features/kavita.nix b/modules/nixos/features/kavita.nix new file mode 100644 index 0000000..c62259e --- /dev/null +++ b/modules/nixos/features/kavita.nix @@ -0,0 +1,25 @@ +{ + config, + ... +}: +let + port = 5015; +in +{ + services = { + kavita = { + enable = true; + dataDir = "/srv/kavita"; + settings.Port = port; + tokenKeyFile = config.age.secrets.kavita.path; + }; + + nginx.virtualHosts."kavita.fi33.buzz" = { + forceSSL = true; + useACMEHost = "fi33.buzz"; + locations."/".proxyPass = "http://localhost:${toString port}"; + }; + }; + + age.secrets.kavita.file = ../../../secrets/kavita.age; +} diff --git a/secrets/kavita.age b/secrets/kavita.age new file mode 100644 index 0000000000000000000000000000000000000000..97f3de850e05cf85dd0a3d49f77d52de0835240c GIT binary patch literal 521 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCSH^a;^+2~-F%F)ufa z2=ofi%6HH3GjuAlaL+2&&a4VCD{^yok1$Ru$;x)g&oNAOcH|1m&I&0@O|~ow2r~D~ zarDfHND0Yx^+|EgNYPIAt;kMJFYqfg3=b;JN=CQMT)QHuGEl*|)F{t9Bf{At&_LVE zI3gp>-6%IQ-NLD$pfJfRr=-L?pt34E!_42P!hp*tJt;Lc(l0%!(kL*$)FaZ{&&@X@ z-^eu7BqdclLc2K3(77NbpxDo^#24K*pAv7&%0Pw4C}(FUmz4BW&vK{2qDn8H5aSdJ zXYI^j^T6wnLqji< zFdxIxTrbl+PapGw@_a5`U0nsEfK-bJGuOlj_f)4+gPPa=@4@X?I&^nD ze_wTi{UHNyXfj)2)pu$3KVtc8y+4Id%Dp&JCt!He`%ls5j!x-XQ;w6BnOD~T<7!U7 mYnwg4GbcIq_Sxr8j;`G~ecM-KUdB~odRIHz<~c8zdKUmPg19aK literal 0 HcmV?d00001 diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 74ef3d4..7f26d4e 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -20,6 +20,7 @@ in "copyparty-will.age".publicKeys = users; "immich.age".publicKeys = users; "jellyfin.age".publicKeys = users; + "kavita.age".publicKeys = users; "lidarr.age".publicKeys = users; "miniflux-creds.age".publicKeys = users; "paperless.age".publicKeys = users; From ea62d6906056907d60ce694c34433b5577d413e0 Mon Sep 17 00:00:00 2001 From: wi11-holdsworth <83637728+wi11-holdsworth@users.noreply.github.com> Date: Mon, 29 Dec 2025 16:47:09 +1100 Subject: [PATCH 6/6] feat: add kavita to dashboard --- modules/nixos/features/homepage-dashboard.nix | 13 +++++++++++++ secrets/kavita-api.age | Bin 0 -> 469 bytes secrets/secrets.nix | 1 + 3 files changed, 14 insertions(+) create mode 100644 secrets/kavita-api.age diff --git a/modules/nixos/features/homepage-dashboard.nix b/modules/nixos/features/homepage-dashboard.nix index 42a4f2a..8d0a871 100644 --- a/modules/nixos/features/homepage-dashboard.nix +++ b/modules/nixos/features/homepage-dashboard.nix @@ -25,6 +25,7 @@ let # keep-sorted start "immich" "jellyfin" + "kavita-api" "lidarr" "miniflux" "paperless" @@ -155,6 +156,18 @@ in }; }; } + { + "Kavita" = { + "description" = "Book reader"; + "icon" = "kavita.svg"; + "href" = "https://kavita.fi33.buzz/"; + "widget" = { + "type" = "kavita"; + "url" = "https://kavita.fi33.buzz/"; + "key" = "@kavita-api@"; + }; + }; + } { "Miniflux" = { "description" = "RSS aggregator"; diff --git a/secrets/kavita-api.age b/secrets/kavita-api.age new file mode 100644 index 0000000000000000000000000000000000000000..0422408b32a713877aa84bb04b6c76feb99b64cd GIT binary patch literal 469 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCSH^a;^+2~^OoC^e`o zHw!58DJk%;D#=VKHj0c&&v3~qGBWZs&JE1-N(~Loh)nm(bma;R$<{UtD9cDH%5o}k zb;>S_N{uMzJE6}sT-ypIqP2b0O((>9+HZ_CO+g#wTK5JTro=lm+?vPjnm@4QfxtZe^+ zh?Ml?loFHtbmu&$;ym*peedvcF5|EqpN!n{?BuM}G~fK-z?6zWg95kUEXR;+A4hLb zXZQ5voI;~Cw=fF>E?r$+1rw9pva~Fdd>`{fPc!GBz?4GEkO0G^KrctbEd3Duq%hZ9 z$Fd^l(6A5#F1wVR9S1MG<5^($yzIQCv?^yYOxx7Je9Tq+mw2bmr?2rJA^