{ inputs, lib, namespace }: let inherit (inputs.nixpkgs.lib) mapAttrs mkOption types toUpper substring stringLength mkDefault mkForce ; base64Lib = import ../base64 { inherit inputs; }; in rec { # Conditionally enable modules based on system enableForSystem = system: modules: builtins.filter ( mod: mod.systems or [ ] == [ ] || builtins.elem system (mod.systems or [ ]) ) modules; # Create a module with common options mkModule = { name, description ? "", options ? { }, moduleConfig ? { }, domain ? "services", config }: let cfg = config.${namespace}.${domain}.${name}; # Create reverse proxy configuration using mkReverseProxy reverseProxyConfig = lib.${namespace}.mkReverseProxy { inherit name; subdomain = cfg.reverseProxy.subdomain; url = "http://${config.${namespace}.network.ipv4.address}:${toString cfg.port}"; # TODO: address middlewares = cfg.reverseProxy.middlewares; }; defaultConfig = { ${namespace}.services.traefik = lib.mkIf cfg.reverseProxy.enable { reverseProxies = [ reverseProxyConfig ]; }; # Open firewall networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; allowedUDPPorts = [ cfg.port ]; }; users = lib.mkIf cfg.createUser { users.${name} = { isSystemUser = true; group = name; home = cfg.configDir; }; groups.${name} = { }; }; services = { postgresql = lib.mkIf cfg.configureDb { enable = true; ensureDatabases = [ name ]; ensureUsers = [ { name = name; ensureDBOwnership = true; } ]; }; redis.servers.${name} = lib.mkIf cfg.redis.enable { enable = true; port = cfg.redis.port; }; }; # systemd.tmpfiles.rules = [ # "d ${cfg.configDir} 0700 ${name} ${name} - -" # # "d ${cfg.configDir}/server-files 0775 ${name} ${name} - -" # # "d ${cfg.configDir}/user-files 0775 ${name} ${name} - -" # ]; } // moduleConfig; in { config, lib, ... }: { options.${namespace}.${domain}.${name} = lib.mkOption { type = lib.types.submodule { options = { enable = lib.mkEnableOption description; port = mkOpt types.int 80 "Port for ${name} to be hosted on"; configDir = mkOpt types.str "/media/nas/main/nix-app-data" "Path to the config dir"; dataDir = mkOpt types.str "/media/nas/main" "Path to the data dir"; createUser = mkBoolOpt false "create a user for this module/service"; configureDb = mkBoolOpt false "Manage db for this service"; environmentFile = mkOpt types.str "" "Environment File"; puid = mkOpt types.str "911" "default user id"; pgid = mkOpt types.str "1000" "default group id"; timeZone = mkOpt types.str "America/Chicago" "default timezone"; listenAddress = mkOpt types.str "0.0.0.0" "Environment File"; openFirewall = mkBoolOpt true "Open the firewall"; redis = { enable = lib.mkEnableOption "enable redis"; port = mkOpt types.int 80 "Port for ${name} redis to be hosted on"; }; hashedPassword = mkOpt (types.nullOr types.str) "$y$j9T$EkPXmsmIMFFZ.WRrBYCxS1$P0kwo6e4.WM5DsqUcEqWC3MrZp5KfCjxffraMFZWu06" "Hashed password for code-server authentication"; extraEnvironment = mkOpt (types.attrsOf types.str) { } "Extra environment variables for code-server"; reverseProxy = mkReverseProxyOpt; } // options; }; default = { }; }; config = lib.mkIf cfg.enable defaultConfig; }; # container mkContainer = { name, localAddress ? "127.0.0.1", ports ? [ "80" ], bindMounts ? { }, config ? { }, }: { lib, ... }: { containers.${name} = { inherit localAddress bindMounts; config = config // { networking = { firewall = { enable = true; allowedTCPPorts = ports; }; # Use systemd-resolved inside the container # Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686 useHostResolvConf = lib.mkForce false; }; services.resolved.enable = true; system.stateVersion = "23.11"; }; autoStart = lib.mkDefault true; privateNetwork = lib.mkDefault true; hostAddress = lib.mkDefault "10.0.1.3"; }; networking = { nat.forwardPorts = map (port: { destination = lib.mkDefault "${localAddress}:${toString port}"; sourcePort = lib.mkDefault port; }) ports; firewall = { allowedTCPPorts = ports; allowedUDPPorts = ports; }; }; }; # Migrated mjallen utilities # Option creation helpers mkOpt = type: default: description: mkOption { inherit type default description; }; mkOpt' = type: default: mkOpt type default null; mkBoolOpt = mkOpt types.bool; mkBoolOpt' = mkOpt' types.bool; mkReverseProxyOpt = { enable = mkBoolOpt false "Enable reverse proxy support"; subdomain = mkOpt types.str "" "subdomain of the service"; middlewares = mkOpt (types.listOf types.str) [ ] "List of middlewares to use"; }; # Standard enable/disable patterns enabled = { enable = true; }; disabled = { enable = false; }; # String utilities capitalize = s: let len = stringLength s; in if len == 0 then "" else (toUpper (substring 0 1 s)) + (substring 1 len s); # Boolean utilities boolToNum = bool: if bool then 1 else 0; # Attribute manipulation utilities default-attrs = mapAttrs (_key: mkDefault); force-attrs = mapAttrs (_key: mkForce); nested-default-attrs = mapAttrs (_key: default-attrs); nested-force-attrs = mapAttrs (_key: force-attrs); } // base64Lib