feat(refactor): ready for merge

This commit is contained in:
2025-10-14 21:50:44 +02:00
parent 63f495fa0d
commit 07333b4544
15 changed files with 125 additions and 85 deletions

View File

@@ -6,7 +6,7 @@
... ...
}: { }: {
flake.nixosConfigurations = let flake.nixosConfigurations = let
cLib = import ../lib inputs.nixpkgs.lib; # clib = import ../lib inputs.nixpkgs.lib;
userConfig = "${self}/home"; userConfig = "${self}/home";
systemConfig = "${self}/system"; systemConfig = "${self}/system";
hostConfig = "${self}/hosts"; hostConfig = "${self}/hosts";
@@ -22,7 +22,7 @@
specialArgs = { specialArgs = {
inherit inherit
cLib # clib
inputs inputs
outputs outputs
self self

View File

@@ -57,12 +57,14 @@
services = { services = {
homepage-dashboard = { homepage-dashboard = {
enable = true; enable = true;
subdomain = ""; subdomain = "dash";
exposure = "local";
port = 8082; port = 8082;
}; };
n8n = { n8n = {
enable = true; enable = true;
subdomain = "n8n"; subdomain = "n8n";
exposure = "local";
port = 5678; port = 5678;
homepage = { homepage = {
name = "n8n"; name = "n8n";
@@ -74,6 +76,7 @@
bazarr = { bazarr = {
enable = true; enable = true;
subdomain = "bazarr"; subdomain = "bazarr";
exposure = "local";
port = 6767; port = 6767;
homepage = { homepage = {
name = "Bazarr"; name = "Bazarr";
@@ -85,6 +88,7 @@
prowlarr = { prowlarr = {
enable = true; enable = true;
subdomain = "prowlarr"; subdomain = "prowlarr";
exposure = "local";
port = 9696; port = 9696;
homepage = { homepage = {
name = "prowlarr"; name = "prowlarr";
@@ -96,6 +100,7 @@
flaresolverr = { flaresolverr = {
enable = true; enable = true;
subdomain = "flaresolverr"; subdomain = "flaresolverr";
exposure = "local";
port = 8191; port = 8191;
homepage = { homepage = {
name = "FlareSolverr"; name = "FlareSolverr";
@@ -107,6 +112,7 @@
lidarr = { lidarr = {
enable = true; enable = true;
subdomain = "lidarr"; subdomain = "lidarr";
exposure = "local";
port = 8686; port = 8686;
homepage = { homepage = {
name = "Lidarr"; name = "Lidarr";
@@ -118,6 +124,7 @@
sonarr = { sonarr = {
enable = true; enable = true;
subdomain = "sonarr"; subdomain = "sonarr";
exposure = "local";
port = 8989; port = 8989;
homepage = { homepage = {
name = "Sonarr"; name = "Sonarr";
@@ -129,6 +136,7 @@
radarr = { radarr = {
enable = true; enable = true;
subdomain = "radarr"; subdomain = "radarr";
exposure = "local";
port = 7878; port = 7878;
homepage = { homepage = {
name = "Radarr"; name = "Radarr";
@@ -140,6 +148,7 @@
jellyseerr = { jellyseerr = {
enable = true; enable = true;
subdomain = "jellyseerr"; subdomain = "jellyseerr";
exposure = "local";
port = 5055; port = 5055;
homepage = { homepage = {
name = "Jellyseerr"; name = "Jellyseerr";
@@ -163,6 +172,7 @@
uptime-kuma = { uptime-kuma = {
enable = true; enable = true;
subdomain = "uptime"; subdomain = "uptime";
exposure = "local";
port = 3001; port = 3001;
homepage = { homepage = {
name = "Uptime Kuma"; name = "Uptime Kuma";
@@ -218,6 +228,7 @@
qbittorrent = { qbittorrent = {
enable = true; enable = true;
subdomain = "qbt"; subdomain = "qbt";
exposure = "local";
port = 8080; port = 8080;
homepage = { homepage = {
name = "qBittorrent"; name = "qBittorrent";
@@ -229,6 +240,7 @@
slskd = { slskd = {
enable = true; enable = true;
subdomain = "slskd"; subdomain = "slskd";
exposure = "local";
port = 5030; port = 5030;
homepage = { homepage = {
name = "Soulseek"; name = "Soulseek";
@@ -240,6 +252,7 @@
pihole = { pihole = {
enable = true; enable = true;
subdomain = "pihole"; subdomain = "pihole";
exposure = "local";
port = 8053; port = 8053;
homepage = { homepage = {
name = "PiHole"; name = "PiHole";

View File

@@ -4,6 +4,10 @@
username = "cnst"; username = "cnst";
mail = "adam@cnst.dev"; mail = "adam@cnst.dev";
sshUser = "sobotka"; sshUser = "sobotka";
domains = {
local = "cnix.dev";
public = "cnst.dev";
};
}; };
}; };
} }

View File

@@ -1,5 +1,26 @@
{ {lib}: let
imports = [ server = {
./serviceurl mkDomain = config: service: let
]; localDomain = config.settings.accounts.domains.local;
publicDomain = config.settings.accounts.domains.public;
tailscaleDomain = "ts.${publicDomain}";
in
if service.exposure == "tunnel"
then publicDomain
else if service.exposure == "tailscale"
then tailscaleDomain
else localDomain;
mkFullDomain = config: service: let
domain = server.mkDomain config service;
in "${service.subdomain}.${domain}";
mkHostDomain = config: service: let
domain = server.mkDomain config service;
in "${domain}";
mkSubDomain = config: service: "${service.subdomain}";
};
in {
server = server;
} }

View File

@@ -1,23 +0,0 @@
{
lib,
config,
...
}: let
mkServiceUrl' = import ./serviceurl.nix {inherit config;};
in {
options.clib = {
server = {
mkServiceUrl = lib.mkOption {
type = lib.types.function;
readOnly = true;
description = "Helper function to generate a service URL.";
};
};
};
config.clib = {
server = {
mkServiceUrl = mkServiceUrl';
};
};
}

View File

@@ -1,11 +0,0 @@
{config}: service: let
mainDomain = config.server.networking.domain;
tailscaleDomain = "ts.${mainDomain}";
domain =
if service.exposure == "tunnel"
then mainDomain
else if service.exposure == "tailscale"
then tailscaleDomain
else (service.domain or mainDomain);
in "${service.subdomain}.${domain}"

View File

@@ -3,7 +3,7 @@
pkgs, pkgs,
lib, lib,
osConfig, osConfig,
cLib, clib,
... ...
}: let }: let
inherit (lib) mkIf mkEnableOption; inherit (lib) mkIf mkEnableOption;
@@ -13,7 +13,7 @@
# hyprlockPkg = pkgs.hyprlock; # hyprlockPkg = pkgs.hyprlock;
# #
bg = osConfig.settings.theme.background; bg = osConfig.settings.theme.background;
inherit (cLib.theme.bgs) resolve; inherit (clib.theme.bgs) resolve;
in { in {
config = mkIf cfg.enable { config = mkIf cfg.enable {
programs.hyprlock = { programs.hyprlock = {

View File

@@ -3,7 +3,7 @@
pkgs, pkgs,
inputs, inputs,
osConfig, osConfig,
cLib, clib,
... ...
}: let }: let
inherit (lib) mkIf; inherit (lib) mkIf;
@@ -11,7 +11,7 @@
cfg = osConfig.nixos.programs.hyprland; cfg = osConfig.nixos.programs.hyprland;
hyprpaperFlake = inputs.hyprpaper.packages.${pkgs.system}.default; hyprpaperFlake = inputs.hyprpaper.packages.${pkgs.system}.default;
bg = osConfig.settings.theme.background; bg = osConfig.settings.theme.background;
bgs = cLib.theme.bgs; bgs = clib.theme.bgs;
monitorMappings = [ monitorMappings = [
{ {

View File

@@ -1,6 +1,14 @@
{self, ...}: { {
self,
lib,
...
}: let
clib = import "${self}/lib/server" {inherit lib;};
in {
imports = [ imports = [
"${self}/lib/server" {
_module.args.clib = clib;
}
./options.nix ./options.nix
./infra ./infra
./services ./services

View File

@@ -1,5 +1,6 @@
{ {
lib, lib,
clib,
config, config,
pkgs, pkgs,
self, self,
@@ -29,21 +30,21 @@
# } # }
# ) (lib.filterAttrs (name: service: service.enable) services); # ) (lib.filterAttrs (name: service: service.enable) services);
generateRouters = services: generateRouters = services: config:
lib.mapAttrs' ( lib.mapAttrs' (
name: service: name: service:
lib.nameValuePair "${service.subdomain}" { lib.nameValuePair name {
entryPoints = ["websecure"]; entryPoints = ["websecure"];
rule = "Host(`${config.clib.server.mkServiceUrl service}`)"; # FIX 3: Use backticks for the Host rule and interpolation
service = service.subdomain; rule = "Host(`${clib.server.mkFullDomain config service}`)";
service = name;
tls.certResolver = "letsencrypt"; tls.certResolver = "letsencrypt";
} }
) (lib.filterAttrs (_: s: s.enable) services); ) (lib.filterAttrs (_: s: s.enable) services);
# Generates all Traefik backend services
generateServices = services: generateServices = services:
lib.mapAttrs' (name: service: lib.mapAttrs' (name: service:
lib.nameValuePair "${service.subdomain}" { lib.nameValuePair name {
loadBalancer.servers = [{url = "http://localhost:${toString service.port}";}]; loadBalancer.servers = [{url = "http://localhost:${toString service.port}";}];
}) (lib.filterAttrs (name: service: service.enable) services); }) (lib.filterAttrs (name: service: service.enable) services);
@@ -168,12 +169,10 @@ in {
dynamicConfigOptions = { dynamicConfigOptions = {
http = { http = {
# Generate the services from your central list
services = generateServices srv.services; services = generateServices srv.services;
# Generate the routers and manually add the special 'api' router
routers = routers =
(generateRouters srv.services) (generateRouters srv.services config)
// { // {
api = { api = {
entryPoints = ["websecure"]; entryPoints = ["websecure"];

View File

@@ -8,10 +8,22 @@
cfg = config.server.infra.${unit}; cfg = config.server.infra.${unit};
srv = config.server; srv = config.server;
generateLocalRecords = services: svcNames = lib.attrNames srv.services;
lib.mapAttrsToList (
name: service: "local-data: \"${service.subdomain}.${srv.domain}. A ${srv.ip}\"" localARecords = builtins.concatLists (map (
) (lib.filterAttrs (name: service: service.enable) services); name: let
s = srv.services.${name};
in
if s != null && s.enable && s.subdomain != null
then [''"${s.subdomain}.${srv.domain}. A ${srv.ip}"'']
else []
)
svcNames);
revParts = lib.lists.reverseList (lib.splitString "." srv.ip);
revName = lib.concatStringsSep "." revParts;
localPTRs = ["${revName}.in-addr.arpa. PTR traefik.${srv.domain}"];
hostIp = hostname: hostIp = hostname:
if hostname == "ziggy" if hostname == "ziggy"
@@ -104,10 +116,10 @@ in {
"255.255.255.255/32" "255.255.255.255/32"
"2001:db8::/32" "2001:db8::/32"
]; ];
local-data = generateLocalRecords srv.services; local-data = localARecords;
local-data-ptr = [
"local-data: \"traefik.${srv.domain}. A ${srv.ip}\"" # Example PTR entry: "14.88.168.192.in-addr.arpa. PTR traefik.cnix.dev."
]; # local-data-ptr = localPTRs;
}; };
}; };
}; };

View File

@@ -12,16 +12,13 @@ in {
age.secrets.giteaCloudflared.file = "${self}/secrets/giteaCloudflared.age"; age.secrets.giteaCloudflared.file = "${self}/secrets/giteaCloudflared.age";
server.infra = { server.infra = {
fail2ban.jails.unit = { fail2ban.jails.${unit} = {
serviceName = "${unit}"; serviceName = "${unit}";
failRegex = '' failRegex = ''.*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>'';
.*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).*
from <HOST>
'';
}; };
postgresql.databases = [ postgresql.databases = [
{database = unit;} {database = "gitea";}
]; ];
}; };

View File

@@ -2,6 +2,7 @@
config, config,
lib, lib,
self, self,
clib,
... ...
}: let }: let
unit = "homepage-dashboard"; unit = "homepage-dashboard";
@@ -90,9 +91,10 @@ in {
"Downloads" "Downloads"
"Services" "Services"
]; ];
allServices = srv.services; allServices = srv.services;
getDomain = s: clib.server.mkHostDomain config s;
homepageServicesFor = category: homepageServicesFor = category:
lib.filterAttrs lib.filterAttrs
( (
@@ -108,12 +110,15 @@ in {
"${cat}" = "${cat}" =
lib.lists.forEach lib.lists.forEach
(lib.attrsets.mapAttrsToList (name: _value: name) (homepageServicesFor cat)) (lib.attrsets.mapAttrsToList (name: _value: name) (homepageServicesFor cat))
(x: { (x: let
"${allServices.${x}.homepage.name}" = { service = allServices.${x};
icon = allServices.${x}.homepage.icon; domain = getDomain service;
description = allServices.${x}.homepage.description; in {
href = "https://${allServices.${x}.url}"; "${service.homepage.name}" = {
siteMonitor = "https://${allServices.${x}.url}"; icon = service.homepage.icon;
description = service.homepage.description;
href = "https://${domain}";
siteMonitor = "https://${domain}";
}; };
}); });
}) })

View File

@@ -2,8 +2,7 @@
lib, lib,
config, config,
... ...
}: }: let
let
inherit (lib) mkOption types; inherit (lib) mkOption types;
sshKeys = { sshKeys = {
@@ -16,14 +15,14 @@ let
keyName = config.settings.accounts.sshUser or null; keyName = config.settings.accounts.sshUser or null;
selectedKey = selectedKey =
if keyName != null then if keyName != null
then
lib.attrByPath [ lib.attrByPath [
keyName keyName
] (builtins.abort "No SSH key defined for hostname/key '${toString keyName}'") sshKeys ] (builtins.abort "No SSH key defined for hostname/key '${toString keyName}'")
else sshKeys
builtins.abort "No accounts.sshUser provided, cannot select SSH key."; else builtins.abort "No accounts.sshUser provided, cannot select SSH key.";
in in {
{
options.settings.accounts = { options.settings.accounts = {
username = mkOption { username = mkOption {
type = types.str; type = types.str;
@@ -46,5 +45,21 @@ in
default = null; default = null;
description = "Optional override for selecting an SSH key by name"; description = "Optional override for selecting an SSH key by name";
}; };
domains = lib.mkOption {
type = lib.types.submodule {
options = {
local = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "The local domain of the host";
};
public = lib.mkOption {
type = lib.types.str;
default = "example.com";
description = "The public domain of the host";
};
};
};
};
}; };
} }

Binary file not shown.