From 7538f734f10066e08728e0ff5687d774a6f9b108 Mon Sep 17 00:00:00 2001 From: mjallen18 Date: Mon, 16 Mar 2026 16:41:46 -0500 Subject: [PATCH] sf --- flake.lock | 215 +++------- flake.nix | 30 +- .../x86_64-linux/admin@jallen-nas/default.nix | 33 +- lib/module/default.nix | 45 ++- modules/home/user/default.nix | 8 +- .../services/esphome/default.nix | 20 + modules/nixos/services/authentik/default.nix | 9 +- modules/nixos/services/traefik/default.nix | 369 ------------------ modules/nixos/services/traefik/options.nix | 42 -- modules/nixos/services/traefik/sops.nix | 76 ---- overlays/ccache/default.nix | 122 ------ overlays/homeassistant/default.nix | 5 - overlays/mjallen-lib/default.nix | 4 + packages/python/littlefs-python/default.nix | 33 ++ secrets/nas-secrets.yaml | 8 +- systems/x86_64-linux/jallen-nas/apps.nix | 10 +- systems/x86_64-linux/jallen-nas/default.nix | 62 +-- systems/x86_64-linux/jallen-nas/disabled.nix | 1 - systems/x86_64-linux/jallen-nas/sops.nix | 18 + 19 files changed, 259 insertions(+), 851 deletions(-) delete mode 100755 modules/nixos/services/traefik/default.nix delete mode 100644 modules/nixos/services/traefik/options.nix delete mode 100644 modules/nixos/services/traefik/sops.nix delete mode 100644 overlays/ccache/default.nix delete mode 100644 overlays/homeassistant/default.nix create mode 100644 overlays/mjallen-lib/default.nix create mode 100644 packages/python/littlefs-python/default.nix diff --git a/flake.lock b/flake.lock index c21e7ae..5d3ec2b 100644 --- a/flake.lock +++ b/flake.lock @@ -24,7 +24,9 @@ "flake-parts": "flake-parts", "flake-utils": "flake-utils", "napalm": "napalm", - "nixpkgs": "nixpkgs", + "nixpkgs": [ + "nixpkgs" + ], "pyproject-build-systems": "pyproject-build-systems", "pyproject-nix": "pyproject-nix", "systems": "systems", @@ -181,7 +183,9 @@ "cosmic": { "inputs": { "flake-compat": "flake-compat_2", - "nixpkgs": "nixpkgs_2", + "nixpkgs": [ + "nixpkgs" + ], "nixpkgs-stable": "nixpkgs-stable", "rust-overlay": "rust-overlay" }, @@ -216,7 +220,7 @@ }, "darwin": { "inputs": { - "nixpkgs": "nixpkgs_3" + "nixpkgs": "nixpkgs" }, "locked": { "lastModified": 1773000227, @@ -444,7 +448,7 @@ }, "flake-utils-plus": { "inputs": { - "flake-utils": "flake-utils_3" + "flake-utils": "flake-utils_2" }, "locked": { "lastModified": 1738591040, @@ -465,24 +469,6 @@ "inputs": { "systems": "systems_2" }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_3": { - "inputs": { - "systems": "systems_3" - }, "locked": { "lastModified": 1694529238, "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", @@ -659,7 +645,7 @@ }, "home-manager_3": { "inputs": { - "nixpkgs": "nixpkgs_7" + "nixpkgs": "nixpkgs_5" }, "locked": { "lastModified": 1760295538, @@ -709,7 +695,7 @@ "impermanence": { "inputs": { "home-manager": "home-manager_2", - "nixpkgs": "nixpkgs_4" + "nixpkgs": "nixpkgs_2" }, "locked": { "lastModified": 1769548169, @@ -749,7 +735,7 @@ "lanzaboote": { "inputs": { "crane": "crane", - "nixpkgs": "nixpkgs_5", + "nixpkgs": "nixpkgs_3", "pre-commit": "pre-commit", "rust-overlay": "rust-overlay_2" }, @@ -820,7 +806,7 @@ "cachyos-kernel-patches": "cachyos-kernel-patches", "flake-compat": "flake-compat_4", "flake-parts": "flake-parts_2", - "nixpkgs": "nixpkgs_6" + "nixpkgs": "nixpkgs_4" }, "locked": { "lastModified": 1773339151, @@ -900,7 +886,7 @@ "nix-plist-manager": { "inputs": { "home-manager": "home-manager_3", - "nixpkgs": "nixpkgs_8" + "nixpkgs": "nixpkgs_6" }, "locked": { "lastModified": 1765533928, @@ -938,7 +924,7 @@ }, "nix-vscode-extensions": { "inputs": { - "nixpkgs": "nixpkgs_9" + "nixpkgs": "nixpkgs_7" }, "locked": { "lastModified": 1773369788, @@ -954,29 +940,10 @@ "type": "github" } }, - "nixai": { - "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": "nixpkgs_10" - }, - "locked": { - "lastModified": 1755942173, - "narHash": "sha256-wSjUhxwartHibNyGrVudc0Zmsv/qgUTL6rBeETl4UTE=", - "owner": "olafkfreund", - "repo": "nix-ai-help", - "rev": "056c3ddc1601b1a8c4d6b1d5cf0ba2d35b8206ee", - "type": "github" - }, - "original": { - "owner": "olafkfreund", - "repo": "nix-ai-help", - "type": "github" - } - }, "nixos-apple-silicon": { "inputs": { "flake-compat": "flake-compat_5", - "nixpkgs": "nixpkgs_11" + "nixpkgs": "nixpkgs_8" }, "locked": { "lastModified": 1772952158, @@ -1010,16 +977,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1771848320, - "narHash": "sha256-0MAd+0mun3K/Ns8JATeHT1sX28faLII5hVLq0L3BdZU=", + "lastModified": 1765934234, + "narHash": "sha256-pJjWUzNnjbIAMIc5gRFUuKCDQ9S1cuh3b2hKgA7Mc4A=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2fc6539b481e1d2569f25f8799236694180c0993", + "rev": "af84f9d270d404c17699522fab95bbf928a2d92f", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-unstable", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } @@ -1119,54 +1086,6 @@ } }, "nixpkgs_10": { - "locked": { - "lastModified": 1751271578, - "narHash": "sha256-P/SQmKDu06x8yv7i0s8bvnnuJYkxVGBWLWHaU+tt4YY=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "3016b4b15d13f3089db8a41ef937b13a9e33a8df", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_11": { - "locked": { - "lastModified": 1768305791, - "narHash": "sha256-AIdl6WAn9aymeaH/NvBj0H9qM+XuAuYbGMZaP0zcXAQ=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "1412caf7bf9e660f2f962917c14b1ea1c3bc695e", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_12": { - "locked": { - "lastModified": 1773389992, - "narHash": "sha256-wvfdLLWJ2I9oEpDd9PfMA8osfIZicoQ5MT1jIwNs9Tk=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "c06b4ae3d6599a672a6210b7021d699c351eebda", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable-small", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_13": { "locked": { "lastModified": 1772736753, "narHash": "sha256-au/m3+EuBLoSzWUCb64a/MZq6QUtOV8oC0D9tY2scPQ=", @@ -1183,38 +1102,6 @@ } }, "nixpkgs_2": { - "locked": { - "lastModified": 1751011381, - "narHash": "sha256-krGXKxvkBhnrSC/kGBmg5MyupUUT5R6IBCLEzx9jhMM=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "30e2e2857ba47844aa71991daa6ed1fc678bcbb7", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_3": { - "locked": { - "lastModified": 1765934234, - "narHash": "sha256-pJjWUzNnjbIAMIc5gRFUuKCDQ9S1cuh3b2hKgA7Mc4A=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "af84f9d270d404c17699522fab95bbf928a2d92f", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_4": { "locked": { "lastModified": 1768564909, "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=", @@ -1230,7 +1117,7 @@ "type": "github" } }, - "nixpkgs_5": { + "nixpkgs_3": { "locked": { "lastModified": 1764950072, "narHash": "sha256-BmPWzogsG2GsXZtlT+MTcAWeDK5hkbGRZTeZNW42fwA=", @@ -1246,7 +1133,7 @@ "type": "github" } }, - "nixpkgs_6": { + "nixpkgs_4": { "locked": { "lastModified": 1773276312, "narHash": "sha256-UujcRqoPEyi0Bd77+cqfAxa4aq0SoKOYTcJNWn+0ZvM=", @@ -1262,7 +1149,7 @@ "type": "github" } }, - "nixpkgs_7": { + "nixpkgs_5": { "locked": { "lastModified": 1759831965, "narHash": "sha256-vgPm2xjOmKdZ0xKA6yLXPJpjOtQPHfaZDRtH+47XEBo=", @@ -1278,7 +1165,7 @@ "type": "github" } }, - "nixpkgs_8": { + "nixpkgs_6": { "locked": { "lastModified": 1757068644, "narHash": "sha256-NOrUtIhTkIIumj1E/Rsv1J37Yi3xGStISEo8tZm3KW4=", @@ -1294,7 +1181,7 @@ "type": "github" } }, - "nixpkgs_9": { + "nixpkgs_7": { "locked": { "lastModified": 1766025857, "narHash": "sha256-Lav5jJazCW4mdg1iHcROpuXqmM94BWJvabLFWaJVJp0=", @@ -1310,6 +1197,38 @@ "type": "github" } }, + "nixpkgs_8": { + "locked": { + "lastModified": 1768305791, + "narHash": "sha256-AIdl6WAn9aymeaH/NvBj0H9qM+XuAuYbGMZaP0zcXAQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "1412caf7bf9e660f2f962917c14b1ea1c3bc695e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_9": { + "locked": { + "lastModified": 1773389992, + "narHash": "sha256-wvfdLLWJ2I9oEpDd9PfMA8osfIZicoQ5MT1jIwNs9Tk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c06b4ae3d6599a672a6210b7021d699c351eebda", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable-small", + "repo": "nixpkgs", + "type": "github" + } + }, "nur": { "inputs": { "flake-parts": [ @@ -1451,10 +1370,9 @@ "nix-plist-manager": "nix-plist-manager", "nix-rosetta-builder": "nix-rosetta-builder", "nix-vscode-extensions": "nix-vscode-extensions", - "nixai": "nixai", "nixos-apple-silicon": "nixos-apple-silicon", "nixos-hardware": "nixos-hardware", - "nixpkgs": "nixpkgs_12", + "nixpkgs": "nixpkgs_9", "nixpkgs-otbr": "nixpkgs-otbr", "nixpkgs-stable": "nixpkgs-stable_2", "nixpkgs-unstable": "nixpkgs-unstable", @@ -1532,7 +1450,7 @@ }, "sops-nix": { "inputs": { - "nixpkgs": "nixpkgs_13" + "nixpkgs": "nixpkgs_10" }, "locked": { "lastModified": 1773096132, @@ -1584,7 +1502,7 @@ "nixpkgs" ], "nur": "nur", - "systems": "systems_4", + "systems": "systems_3", "tinted-foot": "tinted-foot", "tinted-kitty": "tinted-kitty", "tinted-schemes": "tinted-schemes", @@ -1650,21 +1568,6 @@ "type": "github" } }, - "systems_4": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, "tinted-foot": { "flake": false, "locked": { diff --git a/flake.nix b/flake.nix index f4c5af1..5f939db 100644 --- a/flake.nix +++ b/flake.nix @@ -3,6 +3,8 @@ nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable-small"; nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.11"; + # Fork required: openthread-border-router is not yet in nixpkgs-unstable. + # Used by modules/nixos/homeassistant/services/thread/default.nix nixpkgs-otbr.url = "github:mrene/nixpkgs/openthread-border-router"; home-manager-stable = { @@ -19,7 +21,7 @@ home-manager = home-manager-unstable; # The name "snowfall-lib" is required due to how Snowfall Lib processes your - # flake's inputs. + # flake's inputs. Using a personal fork for custom changes. snowfall-lib = { url = "github:mjallen18/snowfall-lib"; inputs.nixpkgs.follows = "nixpkgs"; @@ -46,17 +48,18 @@ inputs.home-manager.follows = "home-manager"; }; - cosmic.url = "github:lilyinstarlight/nixos-cosmic"; + cosmic = { + url = "github:lilyinstarlight/nixos-cosmic"; + inputs.nixpkgs.follows = "nixpkgs"; + }; nix-vscode-extensions.url = "github:nix-community/nix-vscode-extensions"; authentik-nix = { url = "github:nix-community/authentik-nix"; - # inputs.nixpkgs.follows = "nixpkgs-stable"; + inputs.nixpkgs.follows = "nixpkgs"; }; - nixai.url = "github:olafkfreund/nix-ai-help"; - disko = { # the fork is needed for partition attributes support # url = "github:nvmd/disko/gpt-attrs"; @@ -188,13 +191,13 @@ # NAS # # ###################################################### jallen-nas = { + # home-manager is already in systems.modules.nixos above modules = with inputs; [ nixos-hardware.nixosModules.common-pc nixos-hardware.nixosModules.common-cpu-amd nixos-hardware.nixosModules.common-cpu-amd-pstate # nixos-hardware.nixosModules.common-cpu-amd-zenpower nixos-hardware.nixosModules.common-hidpi - home-manager.nixosModules.home-manager ]; }; @@ -202,8 +205,8 @@ # NUC # # ###################################################### nuc-nixos = { + # disko is already in systems.modules.nixos above modules = with inputs; [ - disko.nixosModules.disko nixos-hardware.nixosModules.common-cpu-amd nixos-hardware.nixosModules.common-cpu-amd-pstate # nixos-hardware.nixosModules.common-cpu-amd-zenpower @@ -217,9 +220,8 @@ # Pi5 # # ###################################################### pi5 = { - modules = with inputs; [ - disko.nixosModules.disko - ]; + # disko is already in systems.modules.nixos above + modules = [ ]; }; # ###################################################### @@ -278,13 +280,7 @@ outputs-builder = channels: { formatter = inputs.treefmt-nix.lib.mkWrapper channels.nixpkgs ./treefmt.nix; - - # Add mjallen-lib to the flake outputs - overlays = { - mjallen-lib = _final: _prev: { - mjallen-lib = (import ./lib { inherit inputs; }).mjallen-lib; - }; - }; + # mjallen-lib overlay is auto-discovered from overlays/mjallen-lib/default.nix }; }; } diff --git a/homes/x86_64-linux/admin@jallen-nas/default.nix b/homes/x86_64-linux/admin@jallen-nas/default.nix index 11613d5..551f9f1 100755 --- a/homes/x86_64-linux/admin@jallen-nas/default.nix +++ b/homes/x86_64-linux/admin@jallen-nas/default.nix @@ -1,4 +1,9 @@ -{ pkgs, namespace, ... }: +{ + pkgs, + config, + namespace, + ... +}: { home = { username = "admin"; @@ -25,6 +30,10 @@ defaultSopsFile = "/etc/nixos/secrets/secrets.yaml"; validateSopsFiles = false; secrets = { + # NOTE: add the following key to secrets/secrets.yaml via `sops secrets/secrets.yaml` + # before deploying: hass-mcp/token: + "hass-mcp/token" = { }; + "ssh-keys-public/jallen-nas" = { path = "/home/admin/.ssh/id_ed25519.pub"; mode = "0644"; @@ -53,6 +62,15 @@ mode = "0600"; }; }; + + templates."hass-mcp.env" = { + path = "/home/admin/.config/sops/hass-mcp.env"; + mode = "0600"; + content = '' + HA_URL=http://nuc-nixos.local:8123 + HA_TOKEN=${config.sops.placeholder."hass-mcp/token"} + ''; + }; }; programs = { @@ -155,12 +173,13 @@ ]; }; hass-mcp = { - command = "uvx"; - args = [ "hass-mcp" ]; - env = { - HA_URL = "http://nuc-nixos.local:8123"; - HA_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI1ZDM2MTliNWNjMGY0ZGI2OWQzOTQ4Mjk0ZDFmNjAxMCIsImlhdCI6MTc3MDc2MjA1NywiZXhwIjoyMDg2MTIyMDU3fQ.P52jeX8GQcdGdzpbU3NCWZMUjkJZHFnOeR8--jy9dF8"; - }; + # Token is read at runtime from a sops-rendered env file. + # The wrapper script sources ~/.config/sops/hass-mcp.env before launching uvx. + command = "bash"; + args = [ + "-c" + "set -a; source ${"\${HOME}"}/.config/sops/hass-mcp.env; set +a; exec uvx hass-mcp" + ]; }; mcp-server-code-runner = { command = "npm"; diff --git a/lib/module/default.nix b/lib/module/default.nix index f82f2ad..a4ecd7f 100644 --- a/lib/module/default.nix +++ b/lib/module/default.nix @@ -40,18 +40,25 @@ rec { 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}"; - middlewares = cfg.reverseProxy.middlewares; - }; + upstreamUrl = + if cfg.reverseProxy.upstreamUrl != null then + cfg.reverseProxy.upstreamUrl + else + "http://127.0.0.1:${toString cfg.port}"; + + fqdn = "${cfg.reverseProxy.subdomain}.${cfg.reverseProxy.domain}"; defaultConfig = { - ${namespace}.services.traefik = lib.mkIf cfg.reverseProxy.enable { - reverseProxies = [ reverseProxyConfig ]; - }; + # Caddy reverse proxy: when reverseProxy.enable = true, contribute this + # service's virtual host block to the Caddy config. The TLS wildcard + # cert is handled via a (cloudflare_tls) snippet defined in globalConfig. + # services.caddy.virtualHosts.${fqdn} = lib.mkIf cfg.reverseProxy.enable { + # extraConfig = '' + # import cloudflare_tls + # reverse_proxy ${upstreamUrl} + # ${cfg.reverseProxy.extraCaddyConfig} + # ''; + # }; # Open firewall networking.firewall = lib.mkIf cfg.openFirewall { @@ -222,14 +229,20 @@ rec { mkBoolOpt' = mkOpt' types.bool; mkReverseProxyOpt = name: { - enable = mkBoolOpt false "Enable reverse proxy support"; + enable = mkBoolOpt false "Enable Caddy reverse proxy for this service"; - subdomain = mkOpt types.str name "subdomain of the service"; + subdomain = mkOpt types.str name "Subdomain for the service (default: service name)"; - middlewares = mkOpt (types.listOf types.str) [ - "crowdsec" - "whitelist-geoblock" - ] "List of middlewares to use"; + domain = mkOpt types.str "mjallen.dev" "Base domain for the reverse proxy"; + + # Override the upstream URL if the backend is not on localhost at cfg.port. + # Leave empty to use http://127.0.0.1: automatically. + upstreamUrl = + mkOpt (types.nullOr types.str) null + "Override upstream URL (e.g. for services on a different host). Defaults to http://127.0.0.1:."; + + # Extra Caddyfile directives inserted inside the virtual host block. + extraCaddyConfig = mkOpt types.lines "" "Extra Caddyfile directives for this virtual host block"; }; # Standard enable/disable patterns diff --git a/modules/home/user/default.nix b/modules/home/user/default.nix index cede736..ec00719 100644 --- a/modules/home/user/default.nix +++ b/modules/home/user/default.nix @@ -31,7 +31,7 @@ in }; fullName = mkOption { type = types.str; - default = "Austin Horstman"; + default = "Matt Jallen"; description = "The full name of the user."; }; home = mkOption { @@ -41,8 +41,8 @@ in }; icon = mkOption { type = (types.nullOr types.package); - default = pkgs.${namespace}.user-icon; - description = "The profile picture to use for the user."; + default = null; + description = "The profile picture to use for the user. Set to a package whose output is the icon file (e.g. a derivation producing a PNG)."; }; name = mkOption { type = (types.nullOr types.str); @@ -145,7 +145,7 @@ in myip = "${getExe pkgs.curl} ifconfig.me"; # Cryptography - genpass = "${getExe pkgs.openssl} rand - base64 20"; # Generate a random, 20-character password + genpass = "${getExe pkgs.openssl} rand -base64 20"; # Generate a random, 20-character password sha = "shasum -a 256"; # Test checksum }; diff --git a/modules/nixos/homeassistant/services/esphome/default.nix b/modules/nixos/homeassistant/services/esphome/default.nix index 8a42dcb..af3f031 100644 --- a/modules/nixos/homeassistant/services/esphome/default.nix +++ b/modules/nixos/homeassistant/services/esphome/default.nix @@ -1,12 +1,21 @@ { config, lib, + pkgs, namespace, ... }: with lib; let cfg = config.${namespace}.services.home-assistant; + + # ESPHome with littlefs-python added to PYTHONPATH so PlatformIO's + # espressif32 platform builder can import it (needed for LittleFS support). + esphomeWithLittlefs = pkgs.esphome.overridePythonAttrs (oldAttrs: { + makeWrapperArgs = (oldAttrs.makeWrapperArgs or [ ]) ++ [ + "--prefix PYTHONPATH : ${pkgs.${namespace}.littlefs-python}/${pkgs.python3.sitePackages}" + ]; + }); in { config = mkIf cfg.enable { @@ -15,6 +24,17 @@ in enable = true; openFirewall = true; # 6052 address = "0.0.0.0"; + package = esphomeWithLittlefs; + }; + }; + + # Add uv to the ESPHome service PATH so PlatformIO uses the Nix-provided + # binary instead of downloading its own (which would fail due to permissions). + # Also disable MemoryDenyWriteExecute so uv (a native Rust binary) can run. + systemd.services.esphome = { + path = [ pkgs.uv ]; + serviceConfig = { + MemoryDenyWriteExecute = lib.mkForce false; }; }; }; diff --git a/modules/nixos/services/authentik/default.nix b/modules/nixos/services/authentik/default.nix index 5f7993a..368338c 100644 --- a/modules/nixos/services/authentik/default.nix +++ b/modules/nixos/services/authentik/default.nix @@ -5,6 +5,9 @@ ... }: with lib; +# NOTE: AUTHENTIK_TOKEN for the RAC outpost is stored in sops. +# Add jallen-nas/authentik-rac/token to secrets/nas-secrets.yaml and ensure +# jallen-nas/sops.nix declares the "authentik-rac.env" template before deploying. let name = "authentik"; cfg = config.${namespace}.services.${name}; @@ -41,10 +44,12 @@ let volumes = [ "${cfg.configDir}/authentik-rac:/media" ]; + # AUTHENTIK_TOKEN is injected via the sops template "authentik-rac.env" + # defined in systems/x86_64-linux/jallen-nas/sops.nix + environmentFiles = [ config.sops.templates."authentik-rac.env".path ]; environment = { AUTHENTIK_HOST = "https://${name}.mjallen.dev"; - AUTHENTIK_TOKEN = "0XGkB2pXoOTqcCMAjucAtfamvlsIZCPmy1Zri54Ozjj3zzMCvcLwkQPrukfx"; - AUTHENTIK_INSECURE = "false"; # Set to true for self-signed certs + AUTHENTIK_INSECURE = "false"; PUID = toString cfg.puid; PGID = toString cfg.pgid; TZ = cfg.timeZone; diff --git a/modules/nixos/services/traefik/default.nix b/modules/nixos/services/traefik/default.nix deleted file mode 100755 index 6084023..0000000 --- a/modules/nixos/services/traefik/default.nix +++ /dev/null @@ -1,369 +0,0 @@ -{ - config, - lib, - namespace, - ... -}: -with lib; -let - cfg = config.${namespace}.services.traefik; - - # Process reverseProxies into service and router configurations - reverseProxyServiceConfigs = - let - makeService = reverseProxy: nameValuePair reverseProxy.service.name reverseProxy.service.config; - in - listToAttrs (map makeService cfg.reverseProxies); - - reverseProxyRouterConfigs = - let - makeRouter = reverseProxy: nameValuePair reverseProxy.router.subdomain reverseProxy.router.config; - in - listToAttrs (map makeRouter cfg.reverseProxies); - - domain = "mjallen.dev"; - - # Forward services - authUrl = "http://localhost:9000/outpost.goauthentik.io"; - cacheUrl = "http://localhost:9012"; - hassUrl = "http://nuc-nixos.local:8123"; - - # Plugins - traefikPlugins = { - bouncer = { - moduleName = "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"; - version = "v1.4.5"; - }; - geoblock = { - moduleName = "github.com/PascalMinder/geoblock"; - version = "v0.2.5"; - }; - }; - - # Ports - httpPort = 80; - httpsPort = 443; - traefikPort = 8080; - metricsPort = 8082; - - forwardPorts = [ - httpPort - httpsPort - traefikPort - metricsPort - ]; - - # misc - letsEncryptEmail = "jalle008@proton.me"; - configDir = "/media/nas/main/appdata"; -in -{ - imports = [ - ./options.nix - ./sops.nix - ]; - - config = mkIf cfg.enable { - - networking.firewall = { - allowedTCPPorts = forwardPorts; - allowedUDPPorts = forwardPorts; - }; - - # services.traefik = { - # enable = true; - # dataDir = "${configDir}/traefik"; - # group = "jallen-nas"; # group; - # environmentFiles = [ config.sops.templates."traefik.env".path ]; - - # static = { - # # dir = "${configDir}/traefik"; - # settings = { - # entryPoints = { - # web = { - # address = ":${toString httpPort}"; - # asDefault = true; - # http.redirections.entrypoint = { - # to = "websecure"; - # scheme = "https"; - # }; - # }; - - # websecure = { - # address = ":${toString httpsPort}"; - # asDefault = true; - # http.tls.certResolver = "letsencrypt"; - # }; - - # metrics = { - # address = ":${toString metricsPort}"; # Port for metrics - # }; - # }; - - # log = { - # level = "INFO"; - # }; - - # metrics = { - # prometheus = { - # entryPoint = "metrics"; - # addEntryPointsLabels = true; - # addServicesLabels = true; - # buckets = [ - # 0.1 - # 0.3 - # 1.2 - # 5.0 - # ]; # Response time buckets - # }; - # }; - - # certificatesResolvers.letsencrypt.acme = { - # email = letsEncryptEmail; - # storage = "${config.services.traefik.dataDir}/acme.json"; - # dnsChallenge = { - # provider = "cloudflare"; - # resolvers = [ - # "1.1.1.1:53" - # "8.8.8.8:53" - # ]; - # }; - # }; - - # # Access the Traefik dashboard on :8080 - # api = { - # dashboard = true; - # insecure = true; - # }; - - # experimental = { - # plugins = traefikPlugins; - # }; - # }; - # }; - - # dynamic = { - # dir = "/run/traefik"; - # files = { - # "serversTransports".settings.http = { - # serversTransports = { - # internal-https = { - # insecureSkipVerify = true; - # }; - # http1 = { - # serverName = "localhost"; - # disableHTTP2 = true; - # }; - # }; - # }; - - # "middlewares-authentik".settings.http = { - # middlewares = { - # authentik = { - # forwardAuth = { - # tls.insecureSkipVerify = true; - # address = "${authUrl}/auth/traefik"; - # trustForwardHeader = true; - # authResponseHeaders = [ - # "X-authentik-username" - # "X-authentik-groups" - # "X-authentik-email" - # "X-authentik-name" - # "X-authentik-uid" - # "X-authentik-jwt" - # "X-authentik-meta-jwks" - # "X-authentik-meta-outpost" - # "X-authentik-meta-provider" - # "X-authentik-meta-app" - # "X-authentik-meta-version" - # ]; - # }; - # }; - # }; - # }; - - # "middlewares-crowdsec".settings.http = { - # middlewares = { - # crowdsec = { - # plugin = { - # bouncer = { - # enabled = true; - # crowdsecLapiKeyFile = config.sops.secrets."jallen-nas/traefik/crowdsec/lapi-key".path; - # crowdsecLapiScheme = "http"; - # crowdsecLapiHost = "localhost:8181"; - # crowdsecLapiPath = "/"; - # crowdsecLapiTLSInsecureVerify = false; - # crowdsecCapiMachineIdFile = config.sops.secrets."jallen-nas/traefik/crowdsec/capi-machine-id".path; - # crowdsecCapiPasswordFile = config.sops.secrets."jallen-nas/traefik/crowdsec/capi-password".path; - # crowdsecCapiScenarios = [ ]; - # }; - # }; - # }; - # }; - # }; - - # "middlewares-geoblock".settings.http = { - # middlewares = { - # whitelist-geoblock = { - # plugin = { - # geoblock = { - # silentStartUp = false; - # allowLocalRequests = true; - # logLocalRequests = false; - # logAllowedRequests = false; - # logApiRequests = false; - # api = "https://get.geojs.io/v1/ip/country/{ip}"; - # apiTimeoutMs = 500; - # cacheSize = 25; - # forceMonthlyUpdate = true; - # allowUnknownCountries = false; - # unknownCountryApiResponse = "nil"; - # blackListMode = false; - # countries = [ - # "CA" - # "US" - # ]; - # }; - # }; - # }; - # }; - # }; - - # "middlewares-ipallowlist".settings.http = { - # middlewares = { - # internal-ipallowlist = { - # ipAllowList = { - # sourceRange = [ - # "127.0.0.1/32" - # "10.0.1.0/24" - # ]; - # }; - # }; - # }; - # }; - - # "services-auth".settings.http = { - # services = { - # auth.loadBalancer.servers = [ - # { - # url = authUrl; - # } - # ]; - # }; - # }; - - # "services-cache".settings.http = { - # services = { - # cache.loadBalancer = { - # servers = [ - # { - # url = cacheUrl; - # } - # ]; - # serversTransport = "http1"; - # }; - # }; - # }; - - # "services-nginx".settings.http = { - # services = { - # nginx.loadBalancer.servers = [ - # { - # url = "http://localhost:8188"; - # } - # ]; - # }; - # }; - - # "services-generated".settings.http = reverseProxyServiceConfigs; - - # "routers-auth".settings.http = { - # routers = { - # auth = { - # entryPoints = [ "websecure" ]; - # rule = "HostRegexp(`{subdomain:[a-z]+}.mjallen.dev`) && PathPrefix(`/outpost.goauthentik.io/`)"; - # service = "auth"; - # middlewares = [ - # "crowdsec" - # "whitelist-geoblock" - # ]; - # priority = 15; - # tls.certResolver = "letsencrypt"; - # }; - # }; - # }; - - # "routers-matrix2".settings.http = { - # routers = { - # matrix2 = { - # entryPoints = [ "websecure" ]; - # rule = "Host(`matrix.mjallen.dev`) && PathPrefix(`/.well-known/matrix/`)"; - # service = "nginx"; - # middlewares = [ - # "crowdsec" - # "whitelist-geoblock" - # ]; - # priority = 1; - # tls.certResolver = "letsencrypt"; - # }; - # }; - # }; - - # "routers-matrix3".settings.http = { - # routers = { - # matrix3 = { - # entryPoints = [ "websecure" ]; - # rule = "Host(`mjallen.dev`) && PathPrefix(`/.well-known/matrix/`)"; - # service = "nginx"; - # middlewares = [ - # "crowdsec" - # "whitelist-geoblock" - # ]; - # priority = 1; - # tls.certResolver = "letsencrypt"; - # }; - # }; - # }; - - # "routers-cache".settings.http = { - # routers = { - # cache = { - # entryPoints = [ "websecure" ]; - # rule = "Host(`cache.${domain}`)"; - # service = "cache"; - # middlewares = [ ]; - # priority = 10; - # tls.certResolver = "letsencrypt"; - # }; - # }; - # }; - - # "home-assistant".settings.http = { - # services = { - # hass.loadBalancer.servers = [ - # { - # url = hassUrl; - # } - # ]; - # }; - # routers = { - # hass = { - # entryPoints = [ "websecure" ]; - # rule = "Host(`hass.${domain}`)"; - # service = "hass"; - # middlewares = [ - # "crowdsec" - # "whitelist-geoblock" - # # "authentik" - # ]; - # priority = 10; - # tls.certResolver = "letsencrypt"; - # }; - # }; - # }; - # "routers-generated".settings.http = reverseProxyRouterConfigs; - # }; - # }; - # }; - }; -} diff --git a/modules/nixos/services/traefik/options.nix b/modules/nixos/services/traefik/options.nix deleted file mode 100644 index 2bf323b..0000000 --- a/modules/nixos/services/traefik/options.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ lib, namespace, ... }: -with lib; -let - inherit (lib.${namespace}) mkOpt; -in -{ - options.${namespace}.services.traefik = { - enable = mkEnableOption "enable traefik"; - - extraServices = mkOpt (types.listOf ( - types.submodule { - options = { - name = mkOpt types.str "" "Name of the service"; - url = mkOpt types.str "http://localhost:8080" "Url of the service"; - }; - } - )) [ ] "List of extra services to forward"; - - extraRouters = mkOpt (types.listOf ( - types.submodule { - options = { - entryPoints = mkOpt (types.listOf types.str) [ "websecure" ] "Entrypoint"; - subdomain = mkOpt types.str "" "subdomain of the service"; - service = mkOpt types.str "" "name of the service"; - middlewares = mkOpt (types.listOf ( - types.enum [ - "authentik" - "onlyoffice-websocket" - "crowdsec" - "whitelist-geoblock" - "internal-ipallowlist" - ] - )) [ ] "List of middlewares to enable"; - }; - } - )) [ ] "List of extra services to forward"; - - reverseProxies = - mkOpt (types.listOf types.attrs) [ ] - "List of reverse proxy configurations from mkReverseProxy"; - }; -} diff --git a/modules/nixos/services/traefik/sops.nix b/modules/nixos/services/traefik/sops.nix deleted file mode 100644 index 8c6dcda..0000000 --- a/modules/nixos/services/traefik/sops.nix +++ /dev/null @@ -1,76 +0,0 @@ -{ - config, - lib, - namespace, - ... -}: -with lib; -let - cfg = config.${namespace}.services.traefik; -in -{ - - config = mkIf cfg.enable { - sops = { - secrets = { - "jallen-nas/traefik/crowdsec/lapi-key" = { - sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"); - owner = config.users.users.traefik.name; - group = config.users.users.traefik.group; - restartUnits = [ "traefik.service" ]; - }; - - "jallen-nas/traefik/crowdsec/capi-machine-id" = { - sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"); - owner = config.users.users.traefik.name; - group = config.users.users.traefik.group; - restartUnits = [ "traefik.service" ]; - }; - - "jallen-nas/traefik/crowdsec/capi-password" = { - sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"); - owner = config.users.users.traefik.name; - group = config.users.users.traefik.group; - restartUnits = [ "traefik.service" ]; - }; - "jallen-nas/traefik/cloudflare-dns-api-token" = { - sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"); - owner = config.users.users.traefik.name; - group = config.users.users.traefik.group; - restartUnits = [ "traefik.service" ]; - }; - "jallen-nas/traefik/cloudflare-zone-api-token" = { - sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"); - owner = config.users.users.traefik.name; - group = config.users.users.traefik.group; - restartUnits = [ "traefik.service" ]; - }; - "jallen-nas/traefik/cloudflare-api-key" = { - sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"); - owner = config.users.users.traefik.name; - group = config.users.users.traefik.group; - restartUnits = [ "traefik.service" ]; - }; - "jallen-nas/traefik/cloudflare-email" = { - sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml"); - owner = config.users.users.traefik.name; - group = config.users.users.traefik.group; - restartUnits = [ "traefik.service" ]; - }; - }; - templates = { - "traefik.env" = { - content = '' - CLOUDFLARE_DNS_API_TOKEN=${config.sops.placeholder."jallen-nas/traefik/cloudflare-dns-api-token"} - CLOUDFLARE_ZONE_API_TOKEN=${config.sops.placeholder."jallen-nas/traefik/cloudflare-zone-api-token"} - CLOUDFLARE_API_KEY=${config.sops.placeholder."jallen-nas/traefik/cloudflare-api-key"} - CLOUDFLARE_EMAIL=${config.sops.placeholder."jallen-nas/traefik/cloudflare-email"} - ''; - owner = config.users.users.traefik.name; - group = config.users.users.traefik.group; - restartUnits = [ "traefik.service" ]; - }; - }; - }; - }; -} diff --git a/overlays/ccache/default.nix b/overlays/ccache/default.nix deleted file mode 100644 index af84a8a..0000000 --- a/overlays/ccache/default.nix +++ /dev/null @@ -1,122 +0,0 @@ -{ ... }: -_final: _super: { - # ${namespace} = super.${namespace} // { - # linuxPackages_rpi5 = super.linuxPackagesFor ( - # super.${namespace}.linux-rpi.override { stdenv = super.ccacheStdenv; } - # ); - # linuxPackages_rpi4 = super.linuxPackagesFor ( - # super.${namespace}.linux-rpi.override { - # stdenv = super.ccacheStdenv; - # rpiVersion = 4; - # } - # ); - # libraspberrypi = super.${namespace}.libraspberrypi.override { stdenv = super.ccacheStdenv; }; - # raspberrypi-utils = super.${namespace}.raspberrypi-utils.override { stdenv = super.ccacheStdenv; }; - - # linuxPackages_cachyos = super.${namespace}.linuxPackages_cachyos.override { - # stdenv = super.ccacheStdenv; - # }; - # # linuxPackages_cachyos-lto = super.${namespace}.linuxPackages_cachyos-lto.override { - # # stdenv = clangCcacheStdenv; - # # }; - # # linuxPackages_cachyos-lto-full = super.${namespace}.linuxPackages_cachyos-lto-full.override { - # # stdenv = clangCcacheStdenv; - # # }; - # linuxPackages_cachyos-lts = super.${namespace}.linuxPackages_cachyos-lts.override { - # stdenv = super.ccacheStdenv; - # }; - # # linuxPackages_cachyos-lts-lto = super.${namespace}.linuxPackages_cachyos-lts-lto.override { - # # stdenv = clangCcacheStdenv; - # # }; - # # linuxPackages_cachyos-lto-znver4 = super.${namespace}.linuxPackages_cachyos-lto-znver4.override { - # # stdenv = clangCcacheStdenv; - # # }; - # linuxPackages_cachyos-server = super.${namespace}.linuxPackages_cachyos-server.override { - # stdenv = super.ccacheStdenv; - # }; - # # linuxPackages_cachyos-server-lto = super.${namespace}.linuxPackages_cachyos-server-lto.override { - # # stdenv = clangCcacheStdenv; - # # }; - # # linuxPackages_cachyos-server-lto-znver4 = - # # super.${namespace}.linuxPackages_cachyos-server-lto-znver4.override - # # { stdenv = clangCcacheStdenv; }; - # linuxPackages_cachyos-rc = super.${namespace}.linuxPackages_cachyos-rc.override { - # stdenv = super.ccacheStdenv; - # }; - # # linuxPackages_cachyos-rc-lto = super.${namespace}.linuxPackages_cachyos-rc-lto.override { - # # stdenv = clangCcacheStdenv; - # # }; - # # linuxPackages_cachyos-rc-lto-znver4 = - # # super.${namespace}.linuxPackages_cachyos-rc-lto-znver4.override - # # { stdenv = clangCcacheStdenv; }; - # linuxPackages_cachyos-hardened = super.${namespace}.linuxPackages_cachyos-hardened.override { - # stdenv = super.ccacheStdenv; - # }; - # # linuxPackages_cachyos-hardened-lto = - # # super.${namespace}.linuxPackages_cachyos-hardened-lto.override - # # { stdenv = clangCcacheStdenv; }; - # # linuxPackages_cachyos-hardened-lto-znver4 = - # # super.${namespace}.linuxPackages_cachyos-hardened-lto-znver4.override - # # { stdenv = clangCcacheStdenv; }; - # linuxPackages_cachyos-deckify = super.${namespace}.linuxPackages_cachyos-deckify.override { - # stdenv = super.ccacheStdenv; - # }; - # # linuxPackages_cachyos-deckify-lto = super.${namespace}.linuxPackages_cachyos-deckify-lto.override { - # # stdenv = clangCcacheStdenv; - # # }; - # }; - - # raspberrypi-utils = super.${namespace}.raspberrypi-utils; - # raspberrypi-udev-rules = super.${namespace}.udev-rules; - # mesa = super.mesa.override { buildPackages.stdenv = super.ccacheStdenv; }; - - # # "webkitgtk_4_1" = super.stable."webkitgtk_4_1".override { clangStdenv = super.ccacheStdenv; }; - # # "webkitgtk_6_0" = super."webkitgtk_6_0".override { clangStdenv = super.ccacheStdenv; }; - - # "jellyfin-ffmpeg" = super."jellyfin-ffmpeg".override { - # ffmpeg_7-full = super.ffmpeg_7-full.override { stdenv = super.ccacheStdenv; }; - # }; - - # # "ffmpeg-headless-rpi" = super."ffmpeg-headless-rpi".override { ffmpeg = super.ffmpeg_7.override { stdenv = super.ccacheStdenv; }; }; - - # # rocmPackages = super.rocmPackages // { - # # hipblaslt = super.rocmPackages.hipblaslt.override { - # # stdenv = super.ccacheStdenv; - # # inherit gpuTargets; - # # }; - # # rocblas = super.rocmPackages.rocblas.override { - # # # stdenv = super.ccacheStdenv; - # # inherit gpuTargets; - # # }; - # # rocsolver = super.rocmPackages.rocsolver.override { - # # # stdenv = super.ccacheStdenv; - # # inherit gpuTargets; - # # }; - # # }; - - # pcsx2 = super.pcsx2.override { - # llvmPackages = super.llvmPackages // { - # stdenv = super.ccacheStdenv; - # }; - # }; - - # driversi686Linux = super.driversi686Linux // { - # mesa = super.driversi686Linux.mesa.override { - # stdenv = super.ccacheStdenv; - # buildPackages = super.driversi686Linux.mesa.buildPackages // { - # stdenv = super.ccacheStdenv; - # }; - # }; - # }; - - # kdePackages = super.kdePackages // { - # qt3d = super.kdePackages.qt3d.override { - # qtbase = super.kdePackages.qtbase.override { stdenv = super.ccacheStdenv; }; - # }; - # qtwebengine = super.stable.kdePackages.qtwebengine; # .override { stdenv = super.ccacheStdenv; }; - # }; - - # # piper-tts = super.piper-tts.overridePythonAttrs (oldAttrs: { - # # pythonCatchConflictsPhase = null; - # # }); -} diff --git a/overlays/homeassistant/default.nix b/overlays/homeassistant/default.nix deleted file mode 100644 index da30b6c..0000000 --- a/overlays/homeassistant/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ ... }: -_final: _prev: { - # home-assistant = final.unstable.home-assistant; - # home-assistant-custom-components = final.unstable.home-assistant-custom-components; -} diff --git a/overlays/mjallen-lib/default.nix b/overlays/mjallen-lib/default.nix new file mode 100644 index 0000000..ba740b8 --- /dev/null +++ b/overlays/mjallen-lib/default.nix @@ -0,0 +1,4 @@ +{ inputs, ... }: +_final: _prev: { + mjallen-lib = (import ../../lib { inherit inputs; }).mjallen-lib; +} diff --git a/packages/python/littlefs-python/default.nix b/packages/python/littlefs-python/default.nix new file mode 100644 index 0000000..f9db988 --- /dev/null +++ b/packages/python/littlefs-python/default.nix @@ -0,0 +1,33 @@ +{ + lib, + python3Packages, +}: + +python3Packages.buildPythonPackage rec { + pname = "littlefs-python"; + version = "0.17.1"; + pyproject = true; + + src = python3Packages.fetchPypi { + pname = "littlefs_python"; + inherit version; + hash = "sha256-O8D9Tnf5T6ZVlRdRfPqj38dCUkcayW4a5fWQaJ4ErtA="; + }; + + build-system = with python3Packages; [ + setuptools + setuptools-scm + cython + ]; + + doCheck = false; + + pythonImportsCheck = [ "littlefs" ]; + + meta = with lib; { + description = "Python bindings for littlefs, the filesystem designed for small embedded targets"; + homepage = "https://github.com/jrast/littlefs-python"; + license = licenses.mit; + maintainers = [ ]; + }; +} diff --git a/secrets/nas-secrets.yaml b/secrets/nas-secrets.yaml index f7566dc..f943c7c 100644 --- a/secrets/nas-secrets.yaml +++ b/secrets/nas-secrets.yaml @@ -3,6 +3,8 @@ jallen-nas: nas_pool: ENC[AES256_GCM,data:LBiUC/5qMFUnWUWYZgRPrGopdPd6oWB0+xe1S+GiOMtSIsBH34ZoE8U/v1HmxR17mt0x169xq7iXAQZTCZ/Vd8KGmecTK7hC+H6kmSUcwsuoPiVyoSPdet3Zb716eXGWmnSD6QlReUpq6xiCqOwKUkgNgRtkdc92PAEcmbrw1tfooxTesxB3n9pSCXAkwsPxJWl7nLrCZIf6wOZci/TiwFJf534/YPKIz8q5JxX+E+VeQ4NNRfZxn4EqlMDgmNcEcuHdflqTNAlDmREqhN0XNREUaFveQ01T5sFb6XHorEHpUlKIzDpMV4LKjZQMZax4T+6nbGpUa5kf/Gr3xeOpMpTGNir1bM8oPQGP/Iz9u4AjGP56+JYcqUBcxG1wwNFIqBrrC+Bf7vdjGxgMClwW5AbMtGXwE9y+dSM9MMkj8kiaK1zWZfyIqRBheXtXUhPIjJSR8fmnVtKW358E7ynC9R14AsA3qxpxEc4+VmF7cJEzjStP//FRSuUFRlvgIcGBfncvt0b+ecEk8WostYAMHhqpyHtW2hG5orv6qFupLz0VCBbFLqlIEMG1d/EfjulGqWN4fGIhlAGpssvuo8r/9bOz4efTwODnKJqX5YfOPhFDAJZzj7pgFgAjf8/xAgelAU1yR3nlj2PR9itEAApY0L0FvnC4fEMBqlpINM8gGeNcfTraIYo7bqVhOT5sVOXmru+nRoyG1I01rJ1lQpis5Kqt+HWGa43fi81dtTm7kj/4bOPSPrJimIOD37O3GRlbiiGIhy/Ta/iVqzRsYeUZOyIQT+IjZ4pX5tgJ/AxASVzdRd9GluexPdUGVDb9Kjf7mo7aYsXyWDBP7ZoXDQGHndrlTlrQreDLgcwCXo1hHEn9YkIUfYpBd5Th7LJrsaNWXH838S+9sDqSCGdVPVcH0HC8x5T5Uo3Jb833uaQjtaXsSaAgaRkcEtAHz4LO5kKii3AgP0vA,iv:ny8qQhSrfokW3iS0KXtCVYgtvj07c25jfEUCIExD7eI=,tag:QD8C37p3gUJr42NHiL7PHw==,type:str] ups_password: ENC[AES256_GCM,data:tYuJ9nU3E2/Ko6Y=,iv:lQq+g68lKCp1rmPvS/84xGIXHxD9zY5zZrrjEJlY8Hs=,tag:p6McEr+sXGAQyMAz1Kaxfw==,type:str] authentik-env: ENC[AES256_GCM,data:PhHiiDJuKx/LKbJR6wx0HknqAs+fnAilA2HsMHwl0N3CMQ0pa+qKEB9x0a16Jr0yC9F4OKD7k98Q4wHbQWuE8IORB9CaiWVQzwJEaFvQ1wdv0wtHC23Aq5ppUPG941xArpF40/64vLYYa8w5Q1wxQr6xeg4VZwpSahIRAa6tB4eMAgopl4QeXGMskaPrL7A9Eu6lXt5LQJkCEFRuyL1XX5W33/l0HYeovgevhqTcbRmOLiG8r4XOihQDUtVWIhW8X3iDlCsgNEgxJE2s+7UuqwetvHpLCQMEyPfITx6FMI6vw8+raLTwQC7fDWXyqjWIJ3/xds7DTcBjJZMj72S6tggX0QLDfnrtjIG0iVNmbRDE2Cv96VJVdV6B381B2XKYx1EThjgucxbmp2Gz4+dpGu3O+rNxlfd9VR7KDA1FH2ddPr8JMhRpeBYbYpxCfuKqgKgfBqvxdI7lV2/alsqLZ3RdzRxi3mCilrldnKEw9YzEJEh0UU2L9J2bP8GJWpyfQsSGnNjpGL3k877e7R0NrKle7ertp2NZKccrKCXyYDGbfERrfmtN2ebaWZXmtbj9Hf/PZBQyXa8onf85QeuY5574pvm8+TZRGorhuMyKi/19lOuEgrAayDM8lQZUDW/QWmU3qf8dO4LAbE7HpzJfv0nEgnKbqVUrV4wcgHYPWNSCFLfdW8eVISgIgZBNA/FD836fwBTCwB91jfWI8g9yrK0l+fvk7RL7Spz7XoK/YIELhojoS6LLr/1wgP2atekDaUBMKw==,iv:w6M8cm+5eCkGPJiD0NkBgZuIVjYPUd9d1yp95y/BwyQ=,tag:SgOpa23x395CefA9zvI5GA==,type:str] + authentik-rac: + token: ENC[AES256_GCM,data:+vI8x8AM9eT35YPQGKmvHH0iZ4IvNUWnSO+05GT57+rC/uRXTaP+PSM+6r6RbUClkd6Pms4HiEEtNxjL,iv:RwNCgBEYLgr/ZgXUbazNJHjCMDXXHIpJQSqSMkFR/Uw=,tag:tqTxdVYOSgxI/IsuypSYdg==,type:str] traefik: crowdsec: lapi-key: ENC[AES256_GCM,data:tEEr+KtGPseweqWn7eyrZwZBl+pPqzQqr5cmlYZF2ugm9pF4sUwBdEy21A==,iv:x1h0Op29Ta15dPe1Tfm4c1Mlo85aqvyOgZ5bELRNTGE=,tag:y0R8DHc0ya96n6hLLhteYA==,type:str] @@ -83,6 +85,8 @@ jallen-nas: nas-pub: ENC[AES256_GCM,data:lZF4LJPDb2EmtDrKsOIrNENBCoEDAYzL8tF5mORGxCKEJXhXB5tnsn0DpzNSaxo+aTlW4AhrH6DdgdlhgAyMqlZRnTLcqc7yUT1zFWEerWvpm0IJJRvyjL4LK6HFuSczQNSwbCylPByvmLm1Tw++wp9RUmZpCxesSH1lgKA=,iv:CAVBEC/byHTpdkgoHzHMFgzCZLoBog2H826/L3Vq4Y0=,tag:s9wp5CjlyYHEKzy3m8+FJA==,type:str] nas-key: ENC[AES256_GCM,data:QGW6jaXZKwFByIoWa0lJXUkIlHZaZEr58hkd+QpUkUUr8g2TEJkb0bAaNNEhhDS8YmQ7HejtgG+YFneji9C9BDPhIFIlM/GPiGzHggHMx3UfJU3ai78UL6sFlito21MhLKox758FIUNnVIa/8zGfLCymy0/eoe+rodX9J/h6cQ==,iv:HBXKoWLTo4usF6L4B1yA9EzM+qZTYfsHOus8nXwQO6w=,tag:BLfLrZKgD/gADwVngMZoqw==,type:str] nas-cert: ENC[AES256_GCM,data:m/eLQPEGWfc8ajF6rHJyyZzuj0UqfnkD/+quDVsY9h55nTFVlky7GbQ2raohs31D8mH7O6AMFsgmkg1vnow7TAuCj06OGhnFHo+oqeqUFIYImfr8cGA+geJJ3dgthSStEzi+gxIKralmWGPVAzcW9DhJm4Y1Ot4mCJ3DRdAALXKjQkO8W7wVfDDSHKKFwwn/Sq4/fdoCanJlxFpLDTuKS4E/CrXC0ojYZJ7ePdx0B/idR4Xm5qxyaE1rysQ45zd9N1HVJlgXi2hHXUCzCxJ5jjx2dht52tkBa+OGWQTQiyXh1gXDhwW2xUkadaKYZ+vPo/VMgZxu44F95/AmuiLGmDumW9hhqlQ7teK897n+R/1HasrUA8Sjshs9Ok9JN/XiZvvO/TJVnEsxdnm5d6xTJ1XI8tHu1A==,iv:dWJIdRj1zWT4Xx0LIZfRENDZWVvDf2XrEizr9+sUr4Q=,tag:uIoLAcpZg1rVP7NYgEgi2A==,type:str] + hass-mcp: + token: ENC[AES256_GCM,data:tt25g4KU8EzaWKBXV4olVp80IlnQYLz8IqJ3ktGorEidmtv+8LZDQu8DG+0hmdh7gT2svyzfSxD/8maWPYsW2GMovDsuR/4qpQ9Lxe06n0mDdeFEBEW38Rz6AFUmNCIxUbNkNoDc7grEIi4kZbTTyNEmxwvzF+VkpddT3VBsm8wXH9F5JW8k4imFzxatCAHCw8R64IzgZe7KL6vEIC0vsHfM8vtZMD85eCZEcV9gIPvQEi/8dApd,iv:8V9VaXvGvZ1dlnLKUTsz3yYjmT9lTxpURdygqVJsteM=,tag:ttfUb7Jd0rtkLCotGgRKVA==,type:str] termix: client-id: ENC[AES256_GCM,data:BKIni/vc+MhzotU28V75kul9+CxSbmO0a1Pw/ySihejXE87hoYW3bQ==,iv:6GObrAqxxOs/Nz58scc/Mt2kIPte55RUK7EYsJ9zbOY=,tag:J5mg17NRm1KD5DrSSV9OOw==,type:str] client-secret: ENC[AES256_GCM,data:mkM+2Ou3kbCiPrw4EN9O5rr6+VkZ0qw3HsY5as2YjlyNnH+7K6WEqVIc2BjahaYMf3Uddj0ObRpqK+eFlO4vKLhx3Oe7cyIfOqLDETSPXoNvT4vCasSnboRLNGOYvHorAKum6BYGD8Kw+LFVkl6YeTmaeA7wvt+5jsOlpu8jajw=,iv:Yq3G+xAP2KjRvQ/grVJRZqfFN/W+tEdEYahhufsczkY=,tag:nSa0cgtu6Mt3IcIzVd3Qkg==,type:str] @@ -233,8 +237,8 @@ sops: L0gwQm5takNjMkVGNzVlSStJYlUwWDAKP8QA3rRUHYbyyhPC/k0Eq2EIKfjyc7Co 7BkHH3msC6h9g42BB5iIYe6KQ+UGxMQBFvp+qSB27jaIfajN5MP0BA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-03-16T16:01:51Z" - mac: ENC[AES256_GCM,data:m1Fb2vGqgpA20v0SsoqfEDmWxF7TLYcv2KROD1E1LZ+Oewx4UN71pj78rbId25vqedx4qL8fpS4FiwK0KrLfruHxSAnR21+PIdgCVxw5mVqvyDxJTZ7GCli8cGHDs4bL0ZlkY1mGZNPF5QWkzUef98XLX4jEkIozJttnNDL/HzM=,iv:E1zPp/rP+wc01Al8sHpzk5iA7POw1Tf9wiZEmVWpNI0=,tag:JYRMKmPWh+ZxQ26qFZmCoA==,type:str] + lastmodified: "2026-03-16T20:25:44Z" + mac: ENC[AES256_GCM,data:BFsr1muH8kY6EehvD1TCfzkn2F8OStso72FuNCkPZBLKxww5895qm+d+pp+STZD2PlUkBLMqEunLNHSNN49Z50OPaGDJTynoes72A5c0beWd/GV/5NM+2vnJ8S3GjquVhlIp2Lfxa4pjMkGdpcZknKoXIQBHwsMkw/ZhJtE1ceQ=,iv:U5YMcKLQG2vXog7XyohLO//0MAfZaFFH4ucPB2RC8iU=,tag:bQY66SUhzhGf2hgO0zT9Hw==,type:str] pgp: - created_at: "2026-02-06T15:34:30Z" enc: |- diff --git a/systems/x86_64-linux/jallen-nas/apps.nix b/systems/x86_64-linux/jallen-nas/apps.nix index e81282c..7931a48 100755 --- a/systems/x86_64-linux/jallen-nas/apps.nix +++ b/systems/x86_64-linux/jallen-nas/apps.nix @@ -28,6 +28,10 @@ in port = 9012; listenAddress = "[::]"; environmentFile = "/run/secrets/jallen-nas/attic-key"; + reverseProxy = { + enable = true; + subdomain = "cache"; + }; }; authentik = { enable = true; @@ -73,6 +77,10 @@ in collabora = { enable = true; port = 9980; + reverseProxy = { + enable = true; + subdomain = "office"; + }; }; crowdsec = { enable = true; @@ -220,8 +228,8 @@ in termix = { enable = true; port = 7777; + reverseProxy = enabled; }; - traefik = disabled; unmanic = { enable = true; port = 8265; diff --git a/systems/x86_64-linux/jallen-nas/default.nix b/systems/x86_64-linux/jallen-nas/default.nix index 851225a..647c6ed 100755 --- a/systems/x86_64-linux/jallen-nas/default.nix +++ b/systems/x86_64-linux/jallen-nas/default.nix @@ -36,6 +36,8 @@ in # # Desktop # # # ################################################### + # COSMIC is enabled for occasional local display access. + # headless.enable only disables watchdog/emergency mode, not the display server. desktop.cosmic = enabled; # ################################################### @@ -69,7 +71,7 @@ in }; }; - headless.enable = true; + headless.enable = false; # ################################################### # # Impermanence # # @@ -96,12 +98,7 @@ in group = "nextcloud"; mode = "u=rwx,g=rwx,o=rx"; } - { - directory = "/plugins-storage"; - user = "traefik"; - group = "traefik"; - mode = "u=rwx,g=rwx,o=rx"; - } + ]; }; @@ -135,22 +132,22 @@ in allowPing = true; trustedInterfaces = [ "tailscale0" ]; allowedTCPPorts = [ - 80 - 443 - 8080 + 80 # http + 443 # https + 8080 # traefik dashboard 8008 # restic 9000 # authentik 2342 # grafana 51820 # wireguard - 1025 - 1143 - 10200 + 1025 # smtp (protonmail bridge) + 1143 # imap (protonmail bridge) + 10200 # nebula 10300 - 8127 + 8127 # llama.cpp server 8280 9943 # onlyoffice - 4000 # netbootxyz - 4080 # netbootxyz + 4000 # netbootxyz tftp/http + 4080 # netbootxyz web 3000 # gitea 2222 # gitea ssh 3300 @@ -161,27 +158,31 @@ in 9012 9988 8192 - 3000 - 2222 - 8181 - 5432 + 8181 # crowdsec 3001 3333 5201 # iperf 8400 - 9200 + 9200 # elasticsearch / attic 9233 9980 - 47984 - 47989 - 47990 - 47998 - 47999 - 48000 - 48010 - 3493 # nut + 47984 # sunshine (tcp: control) + 47989 # sunshine (tcp: https) + 47990 # sunshine (tcp: web) + 47998 # sunshine (tcp: video) + 47999 # sunshine (tcp: control) + 48000 # sunshine (tcp: video) + 48010 # sunshine (tcp: rtsp) + 3493 # nut upsd + # removed: 5432 (postgres — internal only, not for external UDP/TCP) + ]; + allowedUDPPorts = [ + 51820 # wireguard + 5201 # iperf + 47998 # sunshine (udp: video) + 47999 # sunshine (udp: control) + 48000 # sunshine (udp: video) ]; - allowedUDPPorts = config.${namespace}.network.firewall.allowedTCPPorts; }; }; @@ -264,7 +265,6 @@ in "nix-apps" "jallen-nas" "grafana" - "traefik" "62900" "1001" ]; diff --git a/systems/x86_64-linux/jallen-nas/disabled.nix b/systems/x86_64-linux/jallen-nas/disabled.nix index 00a6e39..f9abfbe 100644 --- a/systems/x86_64-linux/jallen-nas/disabled.nix +++ b/systems/x86_64-linux/jallen-nas/disabled.nix @@ -57,7 +57,6 @@ in restic = mkForce disabled; sunshine = mkForce disabled; tdarr = mkForce disabled; - traefik = mkForce disabled; unmanic = mkForce disabled; uptime-kuma = mkForce disabled; wyoming = mkForce disabled; diff --git a/systems/x86_64-linux/jallen-nas/sops.nix b/systems/x86_64-linux/jallen-nas/sops.nix index d65b320..cf5fdd0 100755 --- a/systems/x86_64-linux/jallen-nas/sops.nix +++ b/systems/x86_64-linux/jallen-nas/sops.nix @@ -256,6 +256,16 @@ in "jallen-nas/ntfy/auth-users" = { sopsFile = defaultSops; }; + + # ------------------------------ + # authentik-rac + # NOTE: add to nas-secrets.yaml via `sops secrets/nas-secrets.yaml`: + # jallen-nas/authentik-rac/token: + # ------------------------------ + "jallen-nas/authentik-rac/token" = { + sopsFile = defaultSops; + restartUnits = [ "podman-authenticRac.service" ]; + }; }; # ------------------------------ @@ -278,6 +288,14 @@ in restartUnits = [ "podman-free-games-claimer.service" ]; }; + "authentik-rac.env" = { + content = '' + AUTHENTIK_TOKEN=${config.sops.placeholder."jallen-nas/authentik-rac/token"} + ''; + mode = "0600"; + restartUnits = [ "podman-authenticRac.service" ]; + }; + "paperless.env" = { content = '' PAPERLESS_ADMIN_USER = "mjallen"