This commit is contained in:
mjallen18
2026-03-16 16:41:46 -05:00
parent 742e1703d8
commit 7538f734f1
19 changed files with 259 additions and 851 deletions

215
flake.lock generated
View File

@@ -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": {

View File

@@ -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
};
};
}

View File

@@ -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: <your HA long-lived access 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";

View File

@@ -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:<port> 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:<port>.";
# 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

View File

@@ -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
};

View File

@@ -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;
};
};
};

View File

@@ -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;

View File

@@ -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 <Traefik IP>: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;
# };
# };
# };
};
}

View File

@@ -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";
};
}

View File

@@ -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" ];
};
};
};
};
}

View File

@@ -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;
# # });
}

View File

@@ -1,5 +0,0 @@
{ ... }:
_final: _prev: {
# home-assistant = final.unstable.home-assistant;
# home-assistant-custom-components = final.unstable.home-assistant-custom-components;
}

View File

@@ -0,0 +1,4 @@
{ inputs, ... }:
_final: _prev: {
mjallen-lib = (import ../../lib { inherit inputs; }).mjallen-lib;
}

View File

@@ -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 = [ ];
};
}

View File

@@ -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: |-

View File

@@ -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;

View File

@@ -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"
];

View File

@@ -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;

View File

@@ -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: <authentik RAC outpost 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"