From 191e86045506622073b715d9b6d454ebf658b481 Mon Sep 17 00:00:00 2001 From: marthsincemelee Date: Mon, 20 Apr 2026 14:46:44 +0200 Subject: [PATCH] feat: Homepage --- modules/environments/actual/default.nix | 17 ++++- .../environments/audiobookshelf/default.nix | 10 +++ modules/environments/homepage/bookmarks.nix | 39 +++++++++++ modules/environments/homepage/bookmarks.yaml | 16 ----- modules/environments/homepage/default.nix | 70 ++++++++++++++++++- modules/environments/jellyfin/default.nix | 11 +++ modules/environments/jellyseerr/default.nix | 12 +++- modules/environments/paperless/default.nix | 11 +++ modules/environments/prowlarr/default.nix | 12 ++++ modules/environments/radarr/default.nix | 11 +++ modules/environments/readarr/default.nix | 11 +++ modules/environments/sonarr/default.nix | 11 ++- modules/services/vpn/default.nix | 1 - modules/services/webserver/default.nix | 52 ++++++++++++++ 14 files changed, 259 insertions(+), 25 deletions(-) create mode 100644 modules/environments/homepage/bookmarks.nix delete mode 100644 modules/environments/homepage/bookmarks.yaml diff --git a/modules/environments/actual/default.nix b/modules/environments/actual/default.nix index 67661ee..04d9759 100644 --- a/modules/environments/actual/default.nix +++ b/modules/environments/actual/default.nix @@ -6,11 +6,13 @@ ... }: let - cfg = config.my.profiles.audiobookshelf; + cfg = config.my.profiles.actual; + hostName = config.networking.hostName; + port = 40465; in { options.my.profiles.actual = with lib; { - enable = mkEnableOption "Audio Book Service"; + enable = mkEnableOption "Actual budget service"; }; @@ -19,7 +21,7 @@ in enable = true; openFirewall = true; settings = { - port = 40465; + port = port; hostname = "0.0.0.0"; }; }; @@ -28,6 +30,15 @@ in actual-server ]; + my.homepage.services = [ + { + group = "Finance"; + name = "Actual"; + description = "Budgeting"; + href = "http://${hostName}:${toString port}"; + } + ]; + systemd.services.actual = { after = [ "network-online.target" ]; }; diff --git a/modules/environments/audiobookshelf/default.nix b/modules/environments/audiobookshelf/default.nix index ff37aaf..dd18837 100644 --- a/modules/environments/audiobookshelf/default.nix +++ b/modules/environments/audiobookshelf/default.nix @@ -7,6 +7,7 @@ }: let cfg = config.my.profiles.audiobookshelf; + hostName = config.networking.hostName; in { options.my.profiles.audiobookshelf = with lib; { @@ -26,6 +27,15 @@ in audiobookshelf ]; + my.homepage.services = [ + { + group = "Media"; + name = "Audiobookshelf"; + description = "Audiobooks and podcasts"; + href = "http://${hostName}:63834"; + } + ]; + systemd.services.audiobookshelf = { after = [ "network-online.target" ]; }; diff --git a/modules/environments/homepage/bookmarks.nix b/modules/environments/homepage/bookmarks.nix new file mode 100644 index 0000000..d277db2 --- /dev/null +++ b/modules/environments/homepage/bookmarks.nix @@ -0,0 +1,39 @@ +[ + { + Developer = [ + { + Github = [ + { + abbr = "GH"; + href = "https://github.com/"; + } + ]; + } + ]; + } + { + Social = [ + { + Reddit = [ + { + icon = "reddit.png"; + href = "https://reddit.com/"; + description = "The front page of the internet"; + } + ]; + } + ]; + } + { + Entertainment = [ + { + YouTube = [ + { + abbr = "YT"; + href = "https://youtube.com/"; + } + ]; + } + ]; + } +] diff --git a/modules/environments/homepage/bookmarks.yaml b/modules/environments/homepage/bookmarks.yaml deleted file mode 100644 index 01f47f5..0000000 --- a/modules/environments/homepage/bookmarks.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -- Developer: - - Github: - - abbr: GH - href: https://github.com/ - -- Social: - - Reddit: - - icon: reddit.png - href: https://reddit.com/ - description: The front page of the internet - -- Entertainment: - - YouTube: - - abbr: YT - href: https://youtube.com/ \ No newline at end of file diff --git a/modules/environments/homepage/default.nix b/modules/environments/homepage/default.nix index fdb1b16..6f36adf 100644 --- a/modules/environments/homepage/default.nix +++ b/modules/environments/homepage/default.nix @@ -6,9 +6,69 @@ }: let cfg = config.my.profiles.homepage; + dashboardPort = 8082; + dashboardHost = config.networking.hostName; + dashboardUrl = "http://${dashboardHost}:${toString dashboardPort}"; + + groupedServices = + lib.foldl' + ( + acc: entry: + acc + // { + ${entry.group} = (acc.${entry.group} or [ ]) ++ [ entry ]; + } + ) + { } + config.my.homepage.services; + + homepageServices = lib.mapAttrsToList ( + group: entries: + { + ${group} = map ( + entry: + { + ${entry.name} = builtins.removeAttrs entry [ + "group" + "name" + ]; + } + ) entries; + } + ) groupedServices; in { + options.my.homepage.services = with lib; mkOption { + type = types.listOf ( + types.submodule { + options = { + group = mkOption { + type = types.str; + description = "Homepage service group"; + }; + + name = mkOption { + type = types.str; + description = "Homepage service name"; + }; + + description = mkOption { + type = types.str; + description = "Homepage service description"; + }; + + href = mkOption { + type = types.str; + description = "Homepage service URL"; + }; + }; + } + ); + default = [ ]; + description = "Merged homepage service metadata contributed by repo modules."; + }; + options.my.profiles.homepage = with lib; { enable = mkEnableOption "getHomepage.dev Dashboard"; }; @@ -16,13 +76,17 @@ in config = lib.mkIf cfg.enable { services.homepage-dashboard = { enable = true; - allowedHosts = "jupiter.solar.internal:8082"; - bookmarks = builtins.readFile ./bookmarks.yaml; + listenPort = dashboardPort; + allowedHosts = "${dashboardHost}:${toString dashboardPort},localhost:${toString dashboardPort},127.0.0.1:${toString dashboardPort}"; + bookmarks = import ./bookmarks.nix; + services = homepageServices; }; + users.users.finn.packages = with pkgs; [ homepage-dashboard ]; - programs.chromium.homepageLocation = "http://jupiter.solar.internal:8082"; + + programs.chromium.homepageLocation = dashboardUrl; }; } diff --git a/modules/environments/jellyfin/default.nix b/modules/environments/jellyfin/default.nix index 88e165c..b1989c2 100644 --- a/modules/environments/jellyfin/default.nix +++ b/modules/environments/jellyfin/default.nix @@ -7,6 +7,8 @@ }: let cfg = config.my.profiles.jellyfin; + hostName = config.networking.hostName; + port = 8096; in { options.my.profiles.jellyfin = with lib; { @@ -20,6 +22,15 @@ in openFirewall = true; }; + my.homepage.services = [ + { + group = "Media"; + name = "Jellyfin"; + description = "Media server"; + href = "http://${hostName}:${toString port}"; + } + ]; + systemd.services.jellyfin = { after = [ "network-online.target" ]; }; diff --git a/modules/environments/jellyseerr/default.nix b/modules/environments/jellyseerr/default.nix index 11bbbb3..bbc96b6 100644 --- a/modules/environments/jellyseerr/default.nix +++ b/modules/environments/jellyseerr/default.nix @@ -2,7 +2,8 @@ { config, lib, ... }: let cfg = config.my.profiles.jellyseerr; - inherit (config.networking) domain; + hostName = config.networking.hostName; + port = 5055; in { options.my.profiles.jellyseerr = with lib; { @@ -15,6 +16,15 @@ in openFirewall = true; }; + my.homepage.services = [ + { + group = "Media"; + name = "Jellyseerr"; + description = "Media requests"; + href = "http://${hostName}:${toString port}"; + } + ]; + systemd.services.jellyseerr = { after = [ "network-online.target" ]; }; diff --git a/modules/environments/paperless/default.nix b/modules/environments/paperless/default.nix index 74ed94c..3a16110 100644 --- a/modules/environments/paperless/default.nix +++ b/modules/environments/paperless/default.nix @@ -2,6 +2,7 @@ { config, lib, ... }: let cfg = config.my.profiles.paperless; + hostName = config.networking.hostName; in { options.my.profiles.paperless = with lib; { @@ -31,6 +32,16 @@ in port = cfg.port; # settings = cfg.extraConfig; }; + + my.homepage.services = [ + { + group = "Documents"; + name = "Paperless"; + description = "Document management"; + href = "http://${hostName}:${toString cfg.port}"; + } + ]; + networking.firewall.allowedTCPPorts = [ cfg.port ]; }; } diff --git a/modules/environments/prowlarr/default.nix b/modules/environments/prowlarr/default.nix index 9584d3f..6b1f876 100644 --- a/modules/environments/prowlarr/default.nix +++ b/modules/environments/prowlarr/default.nix @@ -7,6 +7,8 @@ }: let cfg = config.my.profiles.prowlarr; + hostName = config.networking.hostName; + port = 9696; in # domain = config.networking.domain; # port = 9696; @@ -20,6 +22,16 @@ in enable = true; openFirewall = true; }; + + my.homepage.services = [ + { + group = "Media"; + name = "Prowlarr"; + description = "Indexer manager"; + href = "http://${hostName}:${toString port}"; + } + ]; + # # ugly fix for service not having a homedirectory # users.users.prowlarr = { # isSystemUser = true; diff --git a/modules/environments/radarr/default.nix b/modules/environments/radarr/default.nix index a2c1d6f..c7a5cb6 100644 --- a/modules/environments/radarr/default.nix +++ b/modules/environments/radarr/default.nix @@ -7,6 +7,8 @@ }: let cfg = config.my.profiles.radarr; + hostName = config.networking.hostName; + port = 7878; in # domain = config.networking.domain; # port = 7878; @@ -22,6 +24,15 @@ in openFirewall = true; }; + my.homepage.services = [ + { + group = "Media"; + name = "Radarr"; + description = "Movie management"; + href = "http://${hostName}:${toString port}"; + } + ]; + my.profiles.prowlarr.enable = true; systemd.services.radarr = { diff --git a/modules/environments/readarr/default.nix b/modules/environments/readarr/default.nix index e95a623..33c20c1 100644 --- a/modules/environments/readarr/default.nix +++ b/modules/environments/readarr/default.nix @@ -7,6 +7,8 @@ }: let cfg = config.my.profiles.readarr; + hostName = config.networking.hostName; + port = 8787; in # domain = config.networking.domain; # port = 7878; @@ -22,6 +24,15 @@ in openFirewall = true; }; + my.homepage.services = [ + { + group = "Media"; + name = "Readarr"; + description = "Book management"; + href = "http://${hostName}:${toString port}"; + } + ]; + my.profiles.prowlarr.enable = true; systemd.services.readarr = { diff --git a/modules/environments/sonarr/default.nix b/modules/environments/sonarr/default.nix index 084a286..1d2d6bf 100644 --- a/modules/environments/sonarr/default.nix +++ b/modules/environments/sonarr/default.nix @@ -7,7 +7,7 @@ }: let cfg = config.my.profiles.sonarr; - # domain = config.networking.domain; + hostName = config.networking.hostName; port = 8989; in { @@ -22,6 +22,15 @@ in openFirewall = true; }; + my.homepage.services = [ + { + group = "Media"; + name = "Sonarr"; + description = "Series management"; + href = "http://${hostName}:${toString port}"; + } + ]; + my.profiles.prowlarr.enable = true; systemd.services.sonarr = { diff --git a/modules/services/vpn/default.nix b/modules/services/vpn/default.nix index 7702410..bf1fb67 100644 --- a/modules/services/vpn/default.nix +++ b/modules/services/vpn/default.nix @@ -2,7 +2,6 @@ { config, lib, ... }: let cfg = config.my.services.vpn; - inherit (config.networking) domain; in { options.my.services.vpn = with lib; { diff --git a/modules/services/webserver/default.nix b/modules/services/webserver/default.nix index 527835a..1d91bf9 100644 --- a/modules/services/webserver/default.nix +++ b/modules/services/webserver/default.nix @@ -19,6 +19,36 @@ let for this virtual host. ''; }; + homepage = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to expose this virtual host on homepage-dashboard. + ''; + }; + group = lib.mkOption { + type = lib.types.str; + default = "Web"; + description = '' + Homepage service group for this virtual host. + ''; + }; + name = lib.mkOption { + type = lib.types.str; + default = ""; + description = '' + Optional display name for homepage-dashboard. Defaults to the subdomain. + ''; + }; + description = lib.mkOption { + type = lib.types.str; + default = ""; + description = '' + Optional homepage-dashboard description for this virtual host. + ''; + }; + }; port = lib.mkOption { type = with lib.types; nullOr port; default = null; @@ -67,14 +97,18 @@ in { subdomain = "gitea"; port = 8080; + homepage.description = "Git forge"; } { subdomain = "dev"; root = "/var/www/dev"; + homepage.description = "Static site"; } { subdomain = "jellyfin"; port = 8096; + homepage.group = "Media"; + homepage.description = "Media server"; extraConfig = { locations."/socket" = { proxyPass = "http://localhost:8096/"; @@ -109,6 +143,24 @@ in } ]; + my.homepage.services = map ( + vhost: + { + group = vhost.homepage.group; + name = if vhost.homepage.name != "" then vhost.homepage.name else vhost.subdomain; + description = + if vhost.homepage.description != "" then + vhost.homepage.description + else if vhost.root != null then + "Static site" + else if vhost.port != null then + "Reverse proxied service" + else + "Web service"; + href = "https://${vhost.subdomain}.${domain}"; + } + ) (builtins.filter (vhost: vhost.homepage.enable) cfg.virtualHosts); + services = { nginx.enable = false; caddy = {