feat: add globals system

This commit is contained in:
Leon Schwarzäugl 2025-06-29 22:43:04 +02:00
parent 6cac368378
commit 2aa5e0095c
Signed by: swarsel
GPG key ID: 26A54C31F2A4FD84
31 changed files with 833 additions and 528 deletions

File diff suppressed because it is too large Load diff

50
flake.lock generated
View file

@ -270,6 +270,24 @@
} }
}, },
"flake-parts": { "flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1749398372,
"narHash": "sha256-tYBdgS56eXYaWVW3fsnPQ/nFlgWi/Z2Ymhyu21zVM98=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9305fe4e5c2a6fcf5ba6a3ff155720fbe4076569",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_2": {
"inputs": { "inputs": {
"nixpkgs-lib": [ "nixpkgs-lib": [
"lanzaboote", "lanzaboote",
@ -290,9 +308,9 @@
"type": "github" "type": "github"
} }
}, },
"flake-parts_2": { "flake-parts_3": {
"inputs": { "inputs": {
"nixpkgs-lib": "nixpkgs-lib" "nixpkgs-lib": "nixpkgs-lib_2"
}, },
"locked": { "locked": {
"lastModified": 1719994518, "lastModified": 1719994518,
@ -307,7 +325,7 @@
"type": "indirect" "type": "indirect"
} }
}, },
"flake-parts_3": { "flake-parts_4": {
"inputs": { "inputs": {
"nixpkgs-lib": [ "nixpkgs-lib": [
"nur", "nur",
@ -328,7 +346,7 @@
"type": "github" "type": "github"
} }
}, },
"flake-parts_4": { "flake-parts_5": {
"inputs": { "inputs": {
"nixpkgs-lib": [ "nixpkgs-lib": [
"stylix", "stylix",
@ -649,7 +667,7 @@
"inputs": { "inputs": {
"crane": "crane", "crane": "crane",
"flake-compat": "flake-compat_2", "flake-compat": "flake-compat_2",
"flake-parts": "flake-parts", "flake-parts": "flake-parts_2",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"pre-commit-hooks-nix": "pre-commit-hooks-nix", "pre-commit-hooks-nix": "pre-commit-hooks-nix",
"rust-overlay": "rust-overlay" "rust-overlay": "rust-overlay"
@ -973,6 +991,21 @@
} }
}, },
"nixpkgs-lib": { "nixpkgs-lib": {
"locked": {
"lastModified": 1748740939,
"narHash": "sha256-rQaysilft1aVMwF14xIdGS3sj1yHlI6oKQNBRTF40cc=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "656a64127e9d791a334452c6b6606d17539476e2",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixpkgs-lib_2": {
"locked": { "locked": {
"lastModified": 1719876945, "lastModified": 1719876945,
"narHash": "sha256-Fm2rDDs86sHy0/1jxTOKB1118Q0O3Uc7EC0iXvXKpbI=", "narHash": "sha256-Fm2rDDs86sHy0/1jxTOKB1118Q0O3Uc7EC0iXvXKpbI=",
@ -1247,7 +1280,7 @@
}, },
"nswitch-rcm-nix": { "nswitch-rcm-nix": {
"inputs": { "inputs": {
"flake-parts": "flake-parts_2", "flake-parts": "flake-parts_3",
"nixpkgs": "nixpkgs_6" "nixpkgs": "nixpkgs_6"
}, },
"locked": { "locked": {
@ -1266,7 +1299,7 @@
}, },
"nur": { "nur": {
"inputs": { "inputs": {
"flake-parts": "flake-parts_3", "flake-parts": "flake-parts_4",
"nixpkgs": "nixpkgs_7", "nixpkgs": "nixpkgs_7",
"treefmt-nix": "treefmt-nix" "treefmt-nix": "treefmt-nix"
}, },
@ -1389,6 +1422,7 @@
"inputs": { "inputs": {
"disko": "disko", "disko": "disko",
"emacs-overlay": "emacs-overlay", "emacs-overlay": "emacs-overlay",
"flake-parts": "flake-parts",
"fw-fanctrl": "fw-fanctrl", "fw-fanctrl": "fw-fanctrl",
"home-manager": "home-manager", "home-manager": "home-manager",
"impermanence": "impermanence", "impermanence": "impermanence",
@ -1501,7 +1535,7 @@
"base16-vim": "base16-vim", "base16-vim": "base16-vim",
"firefox-gnome-theme": "firefox-gnome-theme", "firefox-gnome-theme": "firefox-gnome-theme",
"flake-compat": "flake-compat_6", "flake-compat": "flake-compat_6",
"flake-parts": "flake-parts_4", "flake-parts": "flake-parts_5",
"git-hooks": "git-hooks", "git-hooks": "git-hooks",
"gnome-shell": "gnome-shell", "gnome-shell": "gnome-shell",
"home-manager": "home-manager_3", "home-manager": "home-manager_3",

280
flake.nix
View file

@ -83,6 +83,7 @@
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
nix-topology.url = "github:oddlama/nix-topology"; nix-topology.url = "github:oddlama/nix-topology";
flake-parts.url = "github:hercules-ci/flake-parts";
}; };
outputs = outputs =
inputs@{ self inputs@{ self
@ -97,113 +98,192 @@
lib = (nixpkgs.lib // home-manager.lib).extend (_: _: { swarselsystems = import ./lib { inherit self lib inputs outputs systems; }; }); lib = (nixpkgs.lib // home-manager.lib).extend (_: _: { swarselsystems = import ./lib { inherit self lib inputs outputs systems; }; });
in in
{ inputs.flake-parts.lib.mkFlake { inherit inputs; } {
inherit lib; imports = [
./nix/globals.nix
# nixosModules = import ./modules/nixos { inherit lib; }; ];
# homeModules = import ./modules/home { inherit lib; }; flake = { config, ... }:
packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; });
formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt);
overlays = import ./overlays { inherit self lib inputs; };
apps = lib.swarselsystems.forAllSystems (system:
let let
appNames = [
"swarsel-bootstrap"
"swarsel-install"
"swarsel-rebuild"
"swarsel-postinstall"
];
appSet = lib.swarselsystems.mkApps system appNames self;
in
appSet // { inherit (self) outputs;
default = appSet.swarsel-bootstrap; lib = (nixpkgs.lib // home-manager.lib).extend (_: _: { swarselsystems = import ./lib { inherit self lib inputs outputs systems; }; });
}
);
linuxUser = "swarsel";
macUser = "leon.schwarzaeugl";
mkFullHost = host: type: {
${host} =
let
systemFunc = if (type == "nixos") then lib.nixosSystem else inputs.nix-darwin.lib.darwinSystem;
in
systemFunc {
specialArgs = { inherit inputs outputs lib self; inherit (config) globals; };
modules = [
{
node.name = host;
node.secretsDir = ./hosts/${type}/${host}/secrets;
}
# put inports here that are for all hosts
inputs.disko.nixosModules.disko
inputs.sops-nix.nixosModules.sops
inputs.impermanence.nixosModules.impermanence
inputs.lanzaboote.nixosModules.lanzaboote
inputs.fw-fanctrl.nixosModules.default
"${self}/hosts/${type}/${host}"
{
_module.args.primaryUser = linuxUser;
}
] ++
(if (host == "iso") then [
inputs.nix-topology.nixosModules.default
] else
([
# put nixos imports here that are for all servers and normal hosts
inputs.nix-topology.nixosModules.default
"${self}/modules/${type}/common"
inputs.stylix.nixosModules.stylix
inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm
] ++ (if (type == "nixos") then [
inputs.home-manager.nixosModules.home-manager
"${self}/profiles/nixos"
"${self}/modules/nixos/server"
"${self}/modules/nixos/optional"
{
home-manager.users."${linuxUser}".imports = [
# put home-manager imports here that are for all normal hosts
"${self}/modules/home/common"
"${self}/modules/home/server"
"${self}/modules/home/optional"
"${self}/profiles/home"
];
}
] else [
# put nixos imports here that are for darwin hosts
"${self}/modules/darwin/nixos/common"
"${self}/profiles/darwin"
inputs.home-manager.darwinModules.home-manager
{
home-manager.users."${macUser}".imports = [
# put home-manager imports here that are for darwin hosts
"${self}/modules/darwin/home"
"${self}/modules/home/server"
"${self}/modules/home/optional"
"${self}/profiles/home"
];
}
])
));
};
};
mkHalfHost = host: type: pkgs: {
${host} =
let
systemFunc = if (type == "home") then inputs.home-manager.lib.homeManagerConfiguration else inputs.nix-on-droid.lib.nixOnDroidConfiguration;
in
systemFunc
{
inherit pkgs;
extraSpecialArgs = { inherit inputs outputs lib self; };
modules = [ "${self}/hosts/${type}/${host}" ];
};
};
mkFullHostConfigs = hosts: type: lib.foldl (acc: set: acc // set) { } (lib.map (host: mkFullHost host type) hosts);
mkHalfHostConfigs = hosts: type: pkgs: lib.foldl (acc: set: acc // set) { } (lib.map (host: mkHalfHost host type pkgs) hosts);
devShells = lib.swarselsystems.forAllSystems (system:
let
pkgs = lib.swarselsystems.pkgsFor.${system};
checks = self.checks.${system};
in in
{ {
default = pkgs.mkShell { inherit lib;
# plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: {
# buildInputs = [pkgs.nixVersions.latest pkgs.boost];
# patches = (o.patches or []) ++ [ "${self}/nix/nix-plugins.patch" ];
# })}/lib/nix/plugins
NIX_CONFIG = ''
plugin-files = ${pkgs.nix-plugins}/lib/nix/plugins
extra-builtins-file = ${self + /nix/extra-builtins.nix}
'';
inherit (checks.pre-commit-check) shellHook;
buildInputs = checks.pre-commit-check.enabledPackages; # nixosModules = import ./modules/nixos { inherit lib; };
nativeBuildInputs = [ # homeModules = import ./modules/home { inherit lib; };
(builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions. packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; });
# pkgs.nix formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt);
pkgs.home-manager overlays = import ./overlays { inherit self lib inputs; };
pkgs.git
pkgs.just apps = lib.swarselsystems.forAllSystems (system:
pkgs.age let
pkgs.ssh-to-age appNames = [
pkgs.sops "swarsel-bootstrap"
pkgs.statix "swarsel-install"
pkgs.deadnix "swarsel-rebuild"
pkgs.nixpkgs-fmt "swarsel-postinstall"
];
appSet = lib.swarselsystems.mkApps system appNames self;
in
appSet // {
default = appSet.swarsel-bootstrap;
}
);
devShells = lib.swarselsystems.forAllSystems (system:
let
pkgs = lib.swarselsystems.pkgsFor.${system};
checks = self.checks.${system};
in
{
default = pkgs.mkShell {
# plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: {
# buildInputs = [pkgs.nixVersions.latest pkgs.boost];
# patches = (o.patches or []) ++ [ "${self}/nix/nix-plugins.patch" ];
# })}/lib/nix/plugins
NIX_CONFIG = ''
plugin-files = ${pkgs.nix-plugins}/lib/nix/plugins
extra-builtins-file = ${self + /nix/extra-builtins.nix}
'';
inherit (checks.pre-commit-check) shellHook;
buildInputs = checks.pre-commit-check.enabledPackages;
nativeBuildInputs = [
(builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions.
# pkgs.nix
pkgs.home-manager
pkgs.git
pkgs.just
pkgs.age
pkgs.ssh-to-age
pkgs.sops
pkgs.statix
pkgs.deadnix
pkgs.nixpkgs-fmt
];
};
}
);
templates = import ./templates { inherit lib; };
checks = lib.swarselsystems.forAllSystems (system:
let
pkgs = lib.swarselsystems.pkgsFor.${system};
in
import ./checks { inherit self inputs system pkgs; }
);
diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix;
nixosConfigurations = mkFullHostConfigs (lib.swarselsystems.readHosts "nixos") "nixos";
homeConfigurations = mkHalfHostConfigs (lib.swarselsystems.readHosts "home") "home" lib.swarselsystems.pkgsFor.x86_64-linux;
darwinConfigurations = mkFullHostConfigs (lib.swarselsystems.readHosts "darwin") "darwin";
nixOnDroidConfigurations = mkHalfHostConfigs (lib.swarselsystems.readHosts "android") "android" lib.swarselsystems.pkgsFor.aarch64-linux;
topology = lib.swarselsystems.forEachSystem (pkgs: import inputs.nix-topology {
inherit pkgs;
modules = [
"${self}/topology"
{ inherit (self) nixosConfigurations; }
]; ];
}; });
}
);
templates = import ./templates { inherit lib; };
checks = lib.swarselsystems.forAllSystems (system:
let
pkgs = lib.swarselsystems.pkgsFor.${system};
in
import ./checks { inherit self inputs system pkgs; }
);
diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix;
nixosConfigurations =
lib.swarselsystems.mkFullHostConfigs (lib.swarselsystems.readHosts "nixos") "nixos";
homeConfigurations =
# "swarsel@home-manager" = inputs.home-manager.lib.homeManagerConfiguration {
# pkgs = lib.swarselsystems.pkgsFor.x86_64-linux;
# extraSpecialArgs = { inherit inputs outputs; };
# modules = homeModules ++ mixedModules ++ [
# ./hosts/home-manager
# ];
# };
lib.swarselsystems.mkHalfHostConfigs (lib.swarselsystems.readHosts "home") "home" lib.swarselsystems.pkgsFor.x86_64-linux;
darwinConfigurations =
lib.swarselsystems.mkFullHostConfigs (lib.swarselsystems.readHosts "darwin") "darwin";
nixOnDroidConfigurations =
# magicant = inputs.nix-on-droid.lib.nixOnDroidConfiguration {
# pkgs = lib.swarselsystems.pkgsFor.aarch64-linux;
# modules = [
# ./hosts/magicant
# ];
# };
lib.swarselsystems.mkHalfHostConfigs (lib.swarselsystems.readHosts "android") "android" lib.swarselsystems.pkgsFor.aarch64-linux;
topology =
lib.swarselsystems.forEachSystem (pkgs: import inputs.nix-topology {
inherit pkgs;
modules = [
"${self}/topology"
{ inherit (self) nixosConfigurations; }
];
});
nodes = config.nixosConfigurations;
};
systems = [
"x86_64-linux"
"aarch64-linux"
];
}; };
} }

View file

@ -13,6 +13,9 @@ in
"${self}/modules/nixos/common/topology.nix" "${self}/modules/nixos/common/topology.nix"
"${self}/modules/home/common/sharedsetup.nix" "${self}/modules/home/common/sharedsetup.nix"
"${self}/modules/nixos/common/globals.nix"
inputs.home-manager.nixosModules.home-manager inputs.home-manager.nixosModules.home-manager
{ {
home-manager.users."${primaryUser}".imports = [ home-manager.users."${primaryUser}".imports = [

View file

@ -1,8 +1,4 @@
{ self, lib, systems, inputs, outputs, ... }: { self, lib, systems, inputs, ... }:
let
linuxUser = "swarsel";
macUser = "leon.schwarzaeugl";
in
{ {
mkIfElseList = p: yes: no: lib.mkMerge [ mkIfElseList = p: yes: no: lib.mkMerge [
@ -47,88 +43,6 @@ in
forEachSystem = f: lib.genAttrs (import systems) (system: f lib.swarselsystems.pkgsFor.${system}); forEachSystem = f: lib.genAttrs (import systems) (system: f lib.swarselsystems.pkgsFor.${system});
mkFullHost = host: type: {
${host} =
let
systemFunc = if (type == "nixos") then lib.nixosSystem else inputs.nix-darwin.lib.darwinSystem;
in
systemFunc {
specialArgs = { inherit inputs outputs lib self; };
modules = [
{
node.name = host;
node.secretsDir = ../hosts/${type}/${host}/secrets;
}
# put inports here that are for all hosts
inputs.disko.nixosModules.disko
inputs.sops-nix.nixosModules.sops
inputs.impermanence.nixosModules.impermanence
inputs.lanzaboote.nixosModules.lanzaboote
inputs.fw-fanctrl.nixosModules.default
"${self}/hosts/${type}/${host}"
{
_module.args.primaryUser = linuxUser;
}
] ++
(if (host == "iso") then [
inputs.nix-topology.nixosModules.default
] else
([
# put nixos imports here that are for all servers and normal hosts
inputs.nix-topology.nixosModules.default
"${self}/modules/${type}/common"
inputs.stylix.nixosModules.stylix
inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm
] ++ (if (type == "nixos") then [
inputs.home-manager.nixosModules.home-manager
"${self}/profiles/nixos"
"${self}/modules/nixos/server"
"${self}/modules/nixos/optional"
{
home-manager.users."${linuxUser}".imports = [
# put home-manager imports here that are for all normal hosts
"${self}/modules/home/common"
"${self}/modules/home/server"
"${self}/modules/home/optional"
"${self}/profiles/home"
];
}
] else [
# put nixos imports here that are for darwin hosts
"${self}/modules/darwin/nixos/common"
"${self}/profiles/darwin"
inputs.home-manager.darwinModules.home-manager
{
home-manager.users."${macUser}".imports = [
# put home-manager imports here that are for darwin hosts
"${self}/modules/darwin/home"
"${self}/modules/home/server"
"${self}/modules/home/optional"
"${self}/profiles/home"
];
}
])
));
};
};
mkHalfHost = host: type: pkgs: {
${host} =
let
systemFunc = if (type == "home") then inputs.home-manager.lib.homeManagerConfiguration else inputs.nix-on-droid.lib.nixOnDroidConfiguration;
in
systemFunc
{
inherit pkgs;
extraSpecialArgs = { inherit inputs outputs lib self; };
modules = [ "${self}/hosts/${type}/${host}" ];
};
};
mkFullHostConfigs = hosts: type: lib.foldl (acc: set: acc // set) { } (lib.map (host: lib.swarselsystems.mkFullHost host type) hosts);
mkHalfHostConfigs = hosts: type: pkgs: lib.foldl (acc: set: acc // set) { } (lib.map (host: lib.swarselsystems.mkHalfHost host type pkgs) hosts);
readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}"); readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}");
readNix = type: lib.filter (name: name != "default.nix") (lib.attrNames (builtins.readDir "${self}/${type}")); readNix = type: lib.filter (name: name != "default.nix") (lib.attrNames (builtins.readDir "${self}/${type}"));

View file

@ -0,0 +1,75 @@
{ lib, options, ... }:
let
inherit (lib)
mkOption
types
;
in
{
options = {
globals = mkOption {
default = { };
type = types.submodule {
options = {
root = {
hashedPassword = mkOption {
type = types.str;
description = "My root user's password hash.";
};
};
myuser = {
name = mkOption {
type = types.str;
description = "My unix username.";
};
hashedPassword = mkOption {
type = types.str;
description = "My unix password hash.";
};
};
services = mkOption {
type = types.attrsOf (
types.submodule {
options = {
domain = mkOption {
type = types.str;
description = "The domain under which this service can be reached";
};
};
}
);
};
domains = {
me = mkOption {
type = types.str;
description = "My main domain.";
};
personal = mkOption {
type = types.str;
description = "My personal domain.";
};
};
macs = mkOption {
default = { };
type = types.attrsOf types.str;
description = "Known MAC addresses for external devices.";
};
};
};
};
_globalsDefs = mkOption {
type = types.unspecified;
default = options.globals.definitions;
readOnly = true;
internal = true;
};
};
}

View file

@ -24,37 +24,5 @@
isImpermanence = lib.mkEnableOption "use impermanence on this system"; isImpermanence = lib.mkEnableOption "use impermanence on this system";
isSecureBoot = lib.mkEnableOption "use secure boot on this system"; isSecureBoot = lib.mkEnableOption "use secure boot on this system";
}; };
globals = lib.mkOption {
default = { };
type = lib.types.submodule {
options = {
services = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule {
options = {
domain = lib.mkOption {
type = lib.types.str;
description = "Domain that the service runs under";
};
};
}
);
};
domains = {
main = lib.mkOption {
type = lib.types.str;
description = "My main domain.";
};
};
};
};
};
# _globalsDefs = lib.mkOption {
# type = lib.types.unspecified;
# default = options.globals.definitions;
# readOnly = true;
# internal = true;
# };
}; };
} }

View file

@ -12,11 +12,13 @@ in
sops.secrets.swarsel = { owner = "root"; }; sops.secrets.swarsel = { owner = "root"; };
topology.self.services.anki = { topology.self.services.${serviceName} = {
name = lib.mkForce "Anki Sync Server"; name = lib.mkForce "Anki Sync Server";
info = "https://${serviceDomain}"; info = "https://${serviceDomain}";
}; };
globals.services.${serviceName}.domain = serviceDomain;
services.anki-sync-server = { services.anki-sync-server = {
enable = true; enable = true;
port = servicePort; port = servicePort;

View file

@ -8,7 +8,8 @@ in
options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server";
config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" { config = lib.mkIf config.swarselsystems.modules.server."${serviceName}" {
topology.self.services.atuin.info = "https://${serviceDomain}"; topology.self.services.${serviceName}.info = "https://${serviceDomain}";
globals.services.${serviceName}.domain = serviceDomain;
services.atuin = { services.atuin = {
enable = true; enable = true;

View file

@ -30,7 +30,8 @@ in
}; };
}; };
topology.self.services.croc.info = "https://${serviceDomain}"; topology.self.services.${serviceName}.info = "https://${serviceDomain}";
globals.services.${serviceName}.domain = serviceDomain;
services.croc = { services.croc = {
enable = true; enable = true;

View file

@ -1,7 +1,7 @@
{ self, lib, config, ... }: { self, lib, config, ... }:
let let
cfg = config.services.firefly-iii; cfg = config.services.firefly-iii;
fireflyDomain = "stonks.swarsel.win"; serviceDomain = "stonks.swarsel.win";
fireflyUser = "firefly-iii"; fireflyUser = "firefly-iii";
serviceName = "firefly"; serviceName = "firefly";
in in
@ -22,9 +22,10 @@ in
topology.self.services.firefly-iii = { topology.self.services.firefly-iii = {
name = "Firefly-III"; name = "Firefly-III";
info = "https://${fireflyDomain}"; info = "https://${serviceDomain}";
icon = "${self}/topology/images/firefly-iii.png"; icon = "${self}/topology/images/firefly-iii.png";
}; };
globals.services.${serviceName}.domain = serviceDomain;
services = { services = {
firefly-iii = { firefly-iii = {
@ -34,7 +35,7 @@ in
dataDir = "/Vault/data/firefly-iii"; dataDir = "/Vault/data/firefly-iii";
settings = { settings = {
TZ = config.repo.secrets.common.location.timezone; TZ = config.repo.secrets.common.location.timezone;
APP_URL = "https://${fireflyDomain}"; APP_URL = "https://${serviceDomain}";
APP_KEY_FILE = config.sops.secrets.firefly-iii-app-key.path; APP_KEY_FILE = config.sops.secrets.firefly-iii-app-key.path;
APP_ENV = "local"; APP_ENV = "local";
DB_CONNECTION = "sqlite"; DB_CONNECTION = "sqlite";
@ -45,12 +46,12 @@ in
# AUTHENTICATION_GUARD_EMAIL = "X-Email"; # AUTHENTICATION_GUARD_EMAIL = "X-Email";
}; };
enableNginx = true; enableNginx = true;
virtualHost = fireflyDomain; virtualHost = serviceDomain;
}; };
nginx = { nginx = {
virtualHosts = { virtualHosts = {
"${fireflyDomain}" = { "${serviceDomain}" = {
locations = { locations = {
"/api" = { "/api" = {
setOauth2Headers = false; setOauth2Headers = false;
@ -75,7 +76,7 @@ in
}; };
}; };
virtualHosts = { virtualHosts = {
"${fireflyDomain}" = { "${serviceDomain}" = {
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
acmeRoot = null; acmeRoot = null;

View file

@ -23,6 +23,8 @@ in
kanidm-forgejo-client = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; kanidm-forgejo-client = { owner = serviceUser; group = serviceGroup; mode = "0440"; };
}; };
globals.services.${serviceName}.domain = serviceDomain;
services.forgejo = { services.forgejo = {
enable = true; enable = true;
user = serviceUser; user = serviceUser;

View file

@ -44,12 +44,14 @@ in
# }; # };
}; };
topology.self.services.freshrss = { topology.self.services.${serviceName} = {
name = "FreshRSS"; name = "FreshRSS";
info = "https://${serviceDomain}"; info = "https://${serviceDomain}";
icon = "${self}/topology/images/freshrss.png"; icon = "${self}/topology/images/freshrss.png";
}; };
globals.services.${serviceName}.domain = serviceDomain;
services.freshrss = { services.freshrss = {
enable = true; enable = true;
virtualHost = serviceDomain; virtualHost = serviceDomain;

View file

@ -1,4 +1,4 @@
{ lib, config, ... }: { lib, config, globals, ... }:
let let
serviceDomain = "shots.swarsel.win"; serviceDomain = "shots.swarsel.win";
servicePort = 3001; servicePort = 3001;
@ -13,7 +13,8 @@ in
extraGroups = [ "video" "render" "users" ]; extraGroups = [ "video" "render" "users" ];
}; };
topology.self.services.immich.info = "https://${serviceDomain}"; topology.self.services.${serviceName}.info = "https://${serviceDomain}";
globals.services.${serviceName}.domain = serviceDomain;
services.immich = { services.immich = {
enable = true; enable = true;

View file

@ -24,7 +24,8 @@ in
]; ];
}; };
topology.self.services.jellyfin.info = "https://${serviceDomain}"; topology.self.services.${serviceName}.info = "https://${serviceDomain}";
globals.services.${serviceName}.domain = serviceDomain;
services.jellyfin = { services.jellyfin = {
enable = true; enable = true;

View file

@ -1,4 +1,4 @@
{ self, lib, pkgs, config, ... }: { self, lib, pkgs, config, globals, ... }:
let let
certsSopsFile = self + /secrets/certs/secrets.yaml; certsSopsFile = self + /secrets/certs/secrets.yaml;
serviceDomain = "sso.swarsel.win"; serviceDomain = "sso.swarsel.win";
@ -6,7 +6,7 @@ let
serviceUser = "kanidm"; serviceUser = "kanidm";
serviceGroup = serviceUser; serviceGroup = serviceUser;
serviceName = "kanidm"; serviceName = "kanidm";
oauth2ProxyDomain = "soauth.swarsel.win"; oauth2ProxyDomain = globals.services.oauth2Proxy.domain;
in in
{ {
options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselsystems.modules.server."${serviceName}" = lib.mkEnableOption "enable ${serviceName} on server";
@ -37,6 +37,8 @@ in
networking.firewall.allowedTCPPorts = [ servicePort ]; networking.firewall.allowedTCPPorts = [ servicePort ];
globals.services.${serviceName}.domain = serviceDomain;
services = { services = {
kanidm = { kanidm = {
package = pkgs.kanidmWithSecretProvisioning; package = pkgs.kanidmWithSecretProvisioning;

View file

@ -2,7 +2,7 @@
let let
serviceName = "kavita"; serviceName = "kavita";
serviceUser = "kavita"; serviceUser = "kavita";
serviceDomain = "scroll.swarsel.win"; serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
servicePort = 8080; servicePort = 8080;
in in
{ {
@ -25,6 +25,7 @@ in
info = "https://${serviceDomain}"; info = "https://${serviceDomain}";
icon = "${self}/topology/images/kavita.png"; icon = "${self}/topology/images/kavita.png";
}; };
globals.services.${serviceName}.domain = serviceDomain;
services.kavita = { services.kavita = {
enable = true; enable = true;

View file

@ -23,6 +23,7 @@ in
info = "https://${serviceDomain}"; info = "https://${serviceDomain}";
icon = "${self}/topology/images/koillection.png"; icon = "${self}/topology/images/koillection.png";
}; };
globals.services.${serviceName}.domain = serviceDomain;
virtualisation.oci-containers.containers = { virtualisation.oci-containers.containers = {
koillection = { koillection = {

View file

@ -87,6 +87,8 @@ in
}; };
}; };
globals.services.${serviceName}.domain = matrixDomain;
services = { services = {
postgresql = { postgresql = {
enable = true; enable = true;

View file

@ -42,7 +42,8 @@ in
}; };
}; };
topology.self.services."${serviceName}".info = "https://${serviceDomain}"; topology.self.services.${serviceName}.info = "https://${serviceDomain}";
globals.services.${serviceName}.domain = serviceDomain;
services."${serviceName}" = { services."${serviceName}" = {
enable = true; enable = true;

View file

@ -35,6 +35,7 @@ in
networking.firewall.allowedTCPPorts = [ servicePort prometheusPort ]; networking.firewall.allowedTCPPorts = [ servicePort prometheusPort ];
topology.self.services.prometheus.info = "https://${serviceDomain}/${prometheusWebRoot}"; topology.self.services.prometheus.info = "https://${serviceDomain}/${prometheusWebRoot}";
globals.services.${moduleName}.domain = serviceDomain;
services = { services = {
grafana = { grafana = {

View file

@ -38,6 +38,8 @@ in
networking.firewall.allowedTCPPorts = [ 4040 ]; networking.firewall.allowedTCPPorts = [ 4040 ];
globals.services.${serviceName}.domain = serviceDomain;
services.navidrome = { services.navidrome = {
enable = true; enable = true;
openFirewall = true; openFirewall = true;

View file

@ -22,6 +22,9 @@ in
}; };
}; };
globals.services.${serviceName}.domain = serviceDomain;
services = { services = {
nextcloud = { nextcloud = {
enable = true; enable = true;

View file

@ -1,6 +1,6 @@
{ lib, config, ... }: { lib, config, globals, ... }:
let let
kanidmDomain = "sso.swarsel.win"; kanidmDomain = globals.services.kanidm.domain;
oauth2ProxyDomain = "soauth.swarsel.win"; oauth2ProxyDomain = "soauth.swarsel.win";
oauth2ProxyPort = 3004; oauth2ProxyPort = 3004;
in in
@ -137,6 +137,8 @@ in
networking.firewall.allowedTCPPorts = [ oauth2ProxyPort ]; networking.firewall.allowedTCPPorts = [ oauth2ProxyPort ];
globals.services.oauth2Proxy.domain = oauth2ProxyDomain;
services = { services = {
oauth2-proxy = { oauth2-proxy = {
enable = true; enable = true;

View file

@ -25,6 +25,8 @@ in
networking.firewall.allowedTCPPorts = [ servicePort ]; networking.firewall.allowedTCPPorts = [ servicePort ];
globals.services.${serviceName}.domain = serviceDomain;
services = { services = {
paperless = { paperless = {
enable = true; enable = true;

View file

@ -29,7 +29,8 @@ in
}; };
}; };
topology.self.services.radicale.info = "https://${serviceDomain}"; topology.self.services.${serviceName}.info = "https://${serviceDomain}";
globals.services.${serviceName}.domain = serviceDomain;
services.radicale = { services.radicale = {
enable = true; enable = true;

View file

@ -48,6 +48,9 @@ in
{ directory = "/var/lib/containers"; } { directory = "/var/lib/containers"; }
]; ];
topology.self.services.${serviceName}.info = "https://${serviceDomain}";
globals.services.${serviceName}.domain = serviceDomain;
services.nginx = { services.nginx = {
upstreams = { upstreams = {
"${serviceName}" = { "${serviceName}" = {

View file

@ -21,6 +21,8 @@ in
networking.firewall.allowedTCPPorts = [ servicePort ]; networking.firewall.allowedTCPPorts = [ servicePort ];
globals.services.${serviceName}.domain = serviceDomain;
services.syncthing = { services.syncthing = {
enable = true; enable = true;
user = serviceUser; user = serviceUser;

View file

@ -85,6 +85,8 @@ in
prowlarr.info = "https://${serviceDomain}/prowlarr"; prowlarr.info = "https://${serviceDomain}/prowlarr";
}; };
globals.services.transmission.domain = serviceDomain;
services = { services = {
radarr = { radarr = {
enable = true; enable = true;

48
nix/globals.nix Normal file
View file

@ -0,0 +1,48 @@
{ inputs, ... }:
{
flake =
{ config
, lib
, ...
}:
{
globals =
let
globalsSystem = lib.evalModules {
prefix = [ "globals" ];
specialArgs = {
inherit lib;
inherit inputs;
inherit (config) nodes;
};
modules = [
../modules/nixos/common/globals.nix
(
{ lib, ... }:
{
globals = lib.mkMerge (
lib.concatLists (
lib.flip lib.mapAttrsToList config.nodes (
name: cfg:
builtins.addErrorContext "while aggregating globals from nixosConfigurations.${name} into flake-level globals:" cfg.config._globalsDefs
)
)
);
}
)
];
};
in
{
# Make sure the keys of this attrset are trivially evaluatable to avoid infinite recursion,
# therefore we inherit relevant attributes from the config.
inherit (globalsSystem.config.globals)
domains
services
macs
myuser
root
;
};
};
}

View file

@ -1,5 +1,5 @@
{ {
"data": "ENC[AES256_GCM,data:+CYlqWYF5RJ8/uzhGEG5uA638DmLc9vCMwRBiBZVFkUzb7Ja+jAZ5GVy6Sxw5SwqJsmZEdqKdGCV2TzTO1vcDBixJlwQlCQcwFDdi3W7ZokzEMdOP03vgx5qgd3kwwe0fEuBS7byragm6rt4Vg3bkBa4uwq1cnQEjKmGa69UTaG0FScKHBeFkEHLBUwIPgH0H52JRQurd8eCF1MPYKNTulpta8pDFb/OuM11zjdNfxJaoqtTN7I0PvS/RHTTuLtuNOi3vv8rJ+PeR3xj3B6mgBwWAews7MdlyfTrgOMd9BWFgnRrWBK4WcPa9gfOgEF4A1jkrh7l23lRo1xpWZFYhGEOl/zVQn6KsPwKtS8VU1e7gLi8EOSUMMkBPyAMfGu0SpRDUwISU0joVzeEvOZ5CrteB683qUYf16jWWfAx1v/7/gr2H01UGOpUsc/z4CPv5jeYzr2mBEa76wSBqSm9KjDS4uea6bHMFvLyVGDwg+ljzM+L5sAMEOoBSY2Pojb3lZuOwve6NI9R6aRRoKbuhLyHgcIH6dk1Dc9+scvrOeDMbzp2oppqLfW2uiG6mTcfvE5leJxQeeUV23LXhZsCkK2+UU5JfVj9JWLp6EBZWZdpTjOHDrMUdPBJtXvrirUu4W1s3Ny36o05d0esav4m+qEhwJEO3iDSAMRzQMFGdZhQOKgAgqCXyg3wUh47qdx54SMeyyLhQIHkz9AmeCeYmALnOxGrUrNGfnytNvPOA41qlmwD4e4yLeiwAowuWnVfw7GC5UGU9O5/B42VWN4WdsNgY6SdjBaRUaotil/UuDVISTczcwI3+NWqLtC5,iv:WmrLJN951DRaXKDVi7KHURWRRRusPisETUy+BH5U6/s=,tag:u36D+o4sA94D5W7CmjAizw==,type:str]", "data": "ENC[AES256_GCM,data:K6Exxoz4dyUuVSvS0BQOyjCQ7iuicPUJbDYhWtX350/9tOhu9XorVNmI1ezfFEmY8iAdxVy/E3QEEQcO+XjJVEVGKoX8NtAWSMUkRJT/S2MLG0nNt3kcsIhoya3S5SDiblMIA+S/yFJOmsyykgLUynYgR9QL5URdGj2utoSi9+WYvUsbxrlmcxIqk443huoq4AeZp5X+HVSIhq0rby0/Uc62ox6jz4S9CwSNTOc41xI6UNRz96xppqcAhru7NjZxomtbI9LaDBMVVRe+k5GrKCTyjqp7JCaeN19Sba/k7Uh+4VOVokNEEL0cYNIZXh8eBBxT3ogQhAfOZXfp+lWKf1bAZvVFBrXI4cSGjNUDcbYCIa1gv+rdaVMju29ZNBp+Hx9p4WjJz6zFAbC+tjmH6wBjGNz8Zeqn5Mmm755yPgdvsVAW4ZZfB49T6qOjkDnNSltoHw0n49qTVS7AmQRSQvzPERyAte3IyftQ0bIGALE27h5oB6ls7X9EXUPyNqaT1G0trnrq5D8L4C3xqYJB3KriHA7PNfpKyOVM50ryACyuF2QRHeWfBnFu78hQbMg4lWYXnVggZQdeFDaHZUeYpJCmeyehmSl88+v8f6hjV0aDPlYh8Yv7lfJokGyffMNq0ShmT2/FBPu+9iAvk/apcE8KFdlct5qtkRaOeXp2iwnHWr2bYg/JQ4D4/xePvqBfV22Qd2MarA1qW7ggVJNCbKcOSJzwbEjPGjBjkH6crfO4LD/SYmVMgSoSGojdyLc7hsAFoUtdhzfknV6vVF7h0TTIIEVIEYt0HJGIfMk3PQ4Z+4O7PSwZXxctT8d7GvuWA45QMO+Ok3pRxqNmWUxEHrJF75l+lZMnSrtjdR1r+vNPnwJxHOgn/2h0sYYvqGVVZdHapxdi+V6za0f/,iv:xXAjuNpqXRuReAH6dlunrbPgspj2/+VtCV3p+xjtOi0=,tag:m//iBHvmYmWw4vtgojbpFw==,type:str]",
"sops": { "sops": {
"age": [ "age": [
{ {
@ -27,8 +27,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtU240VjVRZmJ5TGsrclJF\nRXRLbTRCZURtR0Z3d2E2eDNNeGRDODlXVEY4CllTeVFYbDJQWlRSS1RFLzAxSnlM\nZi9NU1c3cWo3YWRLcUJ2U2ZFWFBBVEEKLS0tIGtmZU9qSWdBT3RDeStaaFFDSWtk\ndkUzZXJwZUl4LzVxYXdidmxXRnNnclUKyAMZqCKSY/RQvTR4bbjLaPnGKwdBcHXc\nvtiVSrLdIdzMa6id/J07TJH5UesUmcp0wjU41MDa4aMBLy+cXhuBHA==\n-----END AGE ENCRYPTED FILE-----\n" "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtU240VjVRZmJ5TGsrclJF\nRXRLbTRCZURtR0Z3d2E2eDNNeGRDODlXVEY4CllTeVFYbDJQWlRSS1RFLzAxSnlM\nZi9NU1c3cWo3YWRLcUJ2U2ZFWFBBVEEKLS0tIGtmZU9qSWdBT3RDeStaaFFDSWtk\ndkUzZXJwZUl4LzVxYXdidmxXRnNnclUKyAMZqCKSY/RQvTR4bbjLaPnGKwdBcHXc\nvtiVSrLdIdzMa6id/J07TJH5UesUmcp0wjU41MDa4aMBLy+cXhuBHA==\n-----END AGE ENCRYPTED FILE-----\n"
} }
], ],
"lastmodified": "2025-06-14T20:56:55Z", "lastmodified": "2025-07-01T10:27:51Z",
"mac": "ENC[AES256_GCM,data:03b5V3zO7mmoP050rrgBaZqR7ik3eioW3PJt0dKab85zOaOXwyq22Ps7vftRV6tQ5S83dSXsAnXvYmdUQ3F3h0Z4zqHB680r1uJG24kJLik+9Pl1a8SwQFB0/yWCaXfKqCZhXIoektl83oBaoWFoCpTuOtYmdoF3rt2mVounIHM=,iv:vAzVQRgQyIMUbwWCG/r4n/QXP/67QN7B651tIzU4TpU=,tag:zcgKO/8g1VmhXHfU7XyeYA==,type:str]", "mac": "ENC[AES256_GCM,data:RyksomYlwuQTcCfmZqmxMMoanvIzu4FcJ+xlUjbBu9Kb/OU5cp8PJXdA78jY/58GOu9s3fkSD1wFewFrPTwtO8xry4Fvw8smr2wttvDS4c6nJ/9lg3Vab147JCEszqHLxghGV48tChvB2zfhpVy1LoF4y+vixMPIrlTFAw+ICzg=,iv:0LzxSmi8kCweETwQw9+UDpudZvJiTaT9UMLfmi990gQ=,tag:vl2y2f3G+Xn1fWwgkE7NfQ==,type:str]",
"pgp": [ "pgp": [
{ {
"created_at": "2025-06-13T20:13:06Z", "created_at": "2025-06-13T20:13:06Z",