refactor(modules): reduce host repetition

This commit is contained in:
2026-03-28 10:52:59 +00:00
parent 1bb97448a4
commit 94baea90d6
47 changed files with 876 additions and 722 deletions

View File

@@ -11,9 +11,10 @@ Personal Nix flake for four machines:
- `modules/` - flake-parts modules, auto-imported via `import-tree`
- `modules/hosts/` - per-host composition modules
- `modules/hosts/_parts/` - host-private leaf modules like hardware, disks, and services
- `modules/hosts/_parts/` - host-private leaf modules like hardware, disks, and literal networking
- `modules/profiles/` - shared host and user profile bundles
- `modules/_lib/` - local helper functions
- `modules/_notability/`, `modules/_paperless/` - feature-owned scripts and templates
- `apps/` - Nushell apps exposed through the flake
- `secrets/` - SOPS-encrypted secrets
- `flake.nix` - generated flake entrypoint
@@ -27,7 +28,8 @@ This repo uses `den` and organizes configuration around aspects instead of putti
- the machine inventory lives in `modules/inventory.nix`
- shared bundles live in `modules/profiles/{host,user}/`
- host composition happens in `modules/hosts/<host>.nix`
- host-private imports live in `modules/hosts/_parts/<host>/`
- host-private imports live in `modules/hosts/_parts/<host>/` and stay limited to true machine leaf files
- feature-owned services live in top-level modules like `modules/gitea.nix`, `modules/notability.nix`, and `modules/paperless.nix`
- user-level config mostly lives in Home Manager aspects
Common examples:
@@ -35,6 +37,8 @@ Common examples:
- `modules/core.nix` - shared Nix and shell foundation
- `modules/dev-tools.nix` - VCS, language, and developer tooling
- `modules/network.nix` - SSH, fail2ban, and tailscale aspects
- `modules/gitea.nix` - Gitea, Litestream, and backup stack for `michael`
- `modules/notability.nix` - Notability ingest services and user tooling for `tahani`
- `modules/profiles/user/workstation.nix` - shared developer workstation user bundle
- `modules/hosts/michael.nix` - server composition for `michael`
- `modules/hosts/tahani.nix` - server/workstation composition for `tahani`

View File

@@ -6,7 +6,9 @@
}:
with lib; let
cfg = config.local.dock;
inherit (pkgs) stdenv dockutil;
inherit (pkgs) dockutil stdenv;
local = import ../_lib/local.nix;
userHome = local.mkHome local.hosts.chidi.system;
in {
options = {
local.dock = {
@@ -45,7 +47,7 @@ in {
{path = "/System/Applications/Music.app/";}
{path = "/System/Applications/System Settings.app/";}
{
path = "/Users/cschmatzler/Downloads";
path = "${userHome}/Downloads";
section = "others";
options = "--sort name --view grid --display stack";
}
@@ -56,7 +58,7 @@ in {
mkOption {
description = "Username to apply the dock settings to";
type = types.str;
default = "cschmatzler";
default = local.user.name;
};
};
};

19
modules/_lib/caddy.nix Normal file
View File

@@ -0,0 +1,19 @@
let
local = import ./local.nix;
in {
inherit (local) tailscaleHost;
mkTailscaleVHost = {
name,
configText,
}: {
"${local.tailscaleHost name}" = {
extraConfig = ''
tls {
get_certificate tailscale
}
${configText}
'';
};
};
}

34
modules/_lib/hosts.nix Normal file
View File

@@ -0,0 +1,34 @@
{
den,
lib,
}: {
mkUserHost = {
system,
host,
user,
userAspect ? "${host}-${user}",
includes ? [],
homeManager ? null,
}:
(lib.setAttrByPath ["den" "hosts" system host "users" user "aspect"] userAspect)
// (lib.setAttrByPath ["den" "aspects" userAspect] ({inherit includes;}
// lib.optionalAttrs (homeManager != null) {
inherit homeManager;
}));
mkPerHostAspect = {
host,
includes ? [],
darwin ? null,
nixos ? null,
}:
lib.setAttrByPath ["den" "aspects" host "includes"] [
(den.lib.perHost ({inherit includes;}
// lib.optionalAttrs (darwin != null) {
inherit darwin;
}
// lib.optionalAttrs (nixos != null) {
inherit nixos;
}))
];
}

33
modules/_lib/local.nix Normal file
View File

@@ -0,0 +1,33 @@
rec {
user = {
name = "cschmatzler";
fullName = "Christoph Schmatzler";
emails = {
personal = "christoph@schmatzler.com";
work = "christoph@tuist.dev";
icloud = "christoph.schmatzler@icloud.com";
};
};
secretPath = name: "/run/secrets/${name}";
mkHome = system:
if builtins.match ".*-darwin" system != null
then "/Users/${user.name}"
else "/home/${user.name}";
mkHost = system: {
inherit system;
home = mkHome system;
};
hosts = {
chidi = mkHost "aarch64-darwin";
janet = mkHost "aarch64-darwin";
michael = mkHost "x86_64-linux";
tahani = mkHost "x86_64-linux";
};
tailscaleDomain = "manticore-hippocampus.ts.net";
tailscaleHost = name: "${name}.${tailscaleDomain}";
}

44
modules/_lib/secrets.nix Normal file
View File

@@ -0,0 +1,44 @@
{lib}: let
local = import ./local.nix;
in rec {
mkBinarySecret = {
name,
sopsFile,
owner ? null,
group ? null,
path ? local.secretPath name,
}:
{
inherit path sopsFile;
format = "binary";
}
// lib.optionalAttrs (owner != null) {
inherit owner;
}
// lib.optionalAttrs (group != null) {
inherit group;
};
mkUserBinarySecret = {
name,
sopsFile,
owner ? local.user.name,
path ? local.secretPath name,
}:
mkBinarySecret {
inherit name owner path sopsFile;
};
mkServiceBinarySecret = {
name,
sopsFile,
serviceUser,
serviceGroup ? serviceUser,
path ? local.secretPath name,
}:
mkBinarySecret {
inherit name path sopsFile;
group = serviceGroup;
owner = serviceUser;
};
}

62
modules/adguardhome.nix Normal file
View File

@@ -0,0 +1,62 @@
{...}: let
caddyLib = import ./_lib/caddy.nix;
in {
den.aspects.adguardhome.nixos = {config, ...}: {
services.adguardhome = {
enable = true;
host = "127.0.0.1";
port = 10000;
settings = {
dhcp.enabled = false;
dns.upstream_dns = [
"1.1.1.1"
"1.0.0.1"
];
filtering = {
protection_enabled = true;
filtering_enabled = true;
safe_search.enabled = false;
safebrowsing_enabled = true;
blocked_response_ttl = 10;
filters_update_interval = 24;
blocked_services.ids = [
"reddit"
"twitter"
];
};
filters = [
{
enabled = true;
url = "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/adblock/pro.txt";
name = "HaGeZi Multi PRO";
id = 1;
}
{
enabled = true;
url = "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/adblock/tif.txt";
name = "HaGeZi Threat Intelligence Feeds";
id = 2;
}
{
enabled = true;
url = "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/adblock/gambling.txt";
name = "HaGeZi Gambling";
id = 3;
}
{
enabled = true;
url = "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/adblock/nsfw.txt";
name = "HaGeZi NSFW";
id = 4;
}
];
};
};
services.caddy.virtualHosts =
caddyLib.mkTailscaleVHost {
name = "adguard";
configText = "reverse_proxy localhost:${toString config.services.adguardhome.port}";
};
};
}

View File

@@ -1,12 +1,14 @@
{inputs, ...}: {
{inputs, ...}: let
local = import ./_lib/local.nix;
inherit (local) secretPath;
opencodeSecretPath = secretPath "opencode-api-key";
in {
den.aspects.ai-tools.homeManager = {
lib,
pkgs,
inputs',
...
}: let
opencodeSecretPath = "/run/secrets/opencode-api-key";
in {
}: {
home.packages = [
inputs'.llm-agents.packages.pi
pkgs.cog-cli
@@ -35,7 +37,7 @@
".pi/agent/extensions/review.ts".source = ./_ai-tools/extensions/review.ts;
".pi/agent/extensions/session-name.ts".source = ./_ai-tools/extensions/session-name.ts;
".pi/agent/notability" = {
source = ./hosts/_parts/tahani/notability;
source = ./_notability;
recursive = true;
};
".pi/agent/skills/elixir-dev" = {

11
modules/cache.nix Normal file
View File

@@ -0,0 +1,11 @@
{...}: let
caddyLib = import ./_lib/caddy.nix;
in {
den.aspects.cache.nixos = {
services.caddy.virtualHosts =
caddyLib.mkTailscaleVHost {
name = "cache";
configText = "reverse_proxy localhost:32843";
};
};
}

View File

@@ -1,4 +1,7 @@
{inputs, ...}: {
{inputs, ...}: let
local = import ./_lib/local.nix;
userHome = local.mkHome local.hosts.chidi.system;
in {
den.aspects.darwin-system.darwin = {pkgs, ...}: {
imports = [
inputs.nix-homebrew.darwinModules.nix-homebrew
@@ -6,7 +9,7 @@
./_darwin/dock.nix
];
system.primaryUser = "cschmatzler";
system.primaryUser = local.user.name;
# Darwin system utilities
environment.systemPackages = with pkgs; [
@@ -111,7 +114,7 @@
};
nix = {
settings.trusted-users = ["cschmatzler"];
settings.trusted-users = [local.user.name];
gc.interval = {
Weekday = 0;
Hour = 2;
@@ -119,18 +122,16 @@
};
};
users.users.cschmatzler = {
name = "cschmatzler";
home = "/Users/cschmatzler";
users.users.${local.user.name} = {
name = local.user.name;
home = userHome;
isHidden = false;
shell = pkgs.nushell;
};
home-manager.useGlobalPkgs = true;
nix-homebrew = {
enable = true;
user = "cschmatzler";
user = local.user.name;
mutableTaps = true;
taps = {
"homebrew/homebrew-core" = inputs.homebrew-core;

View File

@@ -25,8 +25,19 @@
flake.flakeModules = {
# Shared system foundations
core = ./core.nix;
darwin = ./darwin.nix;
network = ./network.nix;
nixos-system = ./nixos-system.nix;
overlays = ./overlays.nix;
secrets = ./secrets.nix;
# Shared host features
adguardhome = ./adguardhome.nix;
cache = ./cache.nix;
gitea = ./gitea.nix;
notability = ./notability.nix;
opencode = ./opencode.nix;
paperless = ./paperless.nix;
# User environment
ai-tools = ./ai-tools.nix;
@@ -34,7 +45,6 @@
desktop = ./desktop.nix;
dev-tools = ./dev-tools.nix;
email = ./email.nix;
finance = ./finance.nix;
neovim = ./neovim.nix;
shell = ./shell.nix;
ssh-client = ./ssh-client.nix;
@@ -44,7 +54,12 @@
};
den.default.nixos.system.stateVersion = "25.11";
den.default.darwin.system.stateVersion = 6;
den.default.homeManager.home.stateVersion = "25.11";
den.default.homeManager = {
home.stateVersion = "25.11";
programs.home-manager.enable = true;
};
den.default.nixos.home-manager.useGlobalPkgs = true;
den.default.darwin.home-manager.useGlobalPkgs = true;
den.default.includes = [
den.provides.define-user

View File

@@ -2,11 +2,13 @@
inputs,
config,
...
}: {
}: let
local = import ./_lib/local.nix;
in {
flake.deploy.nodes = {
michael = {
hostname = "michael";
sshUser = "cschmatzler";
sshUser = local.user.name;
profiles.system = {
user = "root";
path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos config.flake.nixosConfigurations.michael;
@@ -14,7 +16,7 @@
};
tahani = {
hostname = "tahani";
sshUser = "cschmatzler";
sshUser = local.user.name;
profiles.system = {
user = "root";
path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos config.flake.nixosConfigurations.tahani;

View File

@@ -1,10 +1,12 @@
{...}: {
{...}: let
local = import ./_lib/local.nix;
in {
den.aspects.dev-tools.homeManager = {
pkgs,
lib,
...
}: let
name = "Christoph Schmatzler";
name = local.user.fullName;
in {
home.packages = with pkgs;
[
@@ -85,7 +87,7 @@
settings = {
user = {
name = name;
email = "christoph@schmatzler.com";
email = local.user.emails.personal;
};
git = {
sign-on-push = true;
@@ -117,7 +119,7 @@
revset-aliases = {
"closest_bookmark(to)" = "heads(::to & bookmarks())";
"closest_pushable(to)" = "heads(::to & mutable() & ~description(exact:\"\") & (~empty() | merges()))";
"mine()" = "author(\"christoph@schmatzler.com\")";
"mine()" = "author(\"${local.user.emails.personal}\")";
"wip()" = "mine() ~ immutable()";
"open()" = "mine() ~ ::trunk()";
"current()" = "@:: & mutable()";

View File

@@ -1,4 +1,6 @@
{...}: {
{...}: let
local = import ./_lib/local.nix;
in {
den.aspects.email.homeManager = {pkgs, ...}: {
programs.himalaya = {
enable = true;
@@ -19,13 +21,13 @@
};
accounts.email = {
accounts."christoph@schmatzler.com" = {
accounts.${local.user.emails.personal} = {
primary = true;
maildir.path = "christoph@schmatzler.com";
address = "christoph@schmatzler.com";
userName = "christoph.schmatzler@icloud.com";
realName = "Christoph Schmatzler";
passwordCommand = ["${pkgs.coreutils}/bin/cat" "/run/secrets/tahani-email-password"];
maildir.path = local.user.emails.personal;
address = local.user.emails.personal;
userName = local.user.emails.icloud;
realName = local.user.fullName;
passwordCommand = ["${pkgs.coreutils}/bin/cat" (local.secretPath "tahani-email-password")];
folders = {
inbox = "INBOX";
drafts = "Drafts";

View File

@@ -1,5 +0,0 @@
{...}: {
den.aspects.finance.homeManager = {pkgs, ...}: {
home.packages = [pkgs.hledger];
};
}

166
modules/gitea.nix Normal file
View File

@@ -0,0 +1,166 @@
{lib, ...}: let
secretLib = import ./_lib/secrets.nix {inherit lib;};
in {
den.aspects.gitea.nixos = {
config,
lib,
pkgs,
...
}: {
sops.secrets = {
michael-gitea-litestream =
secretLib.mkServiceBinarySecret {
name = "michael-gitea-litestream";
serviceUser = "gitea";
sopsFile = ../secrets/michael-gitea-litestream;
};
michael-gitea-restic-password =
secretLib.mkServiceBinarySecret {
name = "michael-gitea-restic-password";
serviceUser = "gitea";
sopsFile = ../secrets/michael-gitea-restic-password;
};
michael-gitea-restic-env =
secretLib.mkServiceBinarySecret {
name = "michael-gitea-restic-env";
serviceUser = "gitea";
sopsFile = ../secrets/michael-gitea-restic-env;
};
};
networking.firewall.allowedTCPPorts = [80 443];
services.redis.servers.gitea = {
enable = true;
port = 6380;
bind = "127.0.0.1";
settings = {
maxmemory = "64mb";
maxmemory-policy = "allkeys-lru";
};
};
services.gitea = {
enable = true;
database = {
type = "sqlite3";
path = "/var/lib/gitea/data/gitea.db";
};
settings = {
server = {
ROOT_URL = "https://git.schmatzler.com/";
DOMAIN = "git.schmatzler.com";
HTTP_ADDR = "127.0.0.1";
HTTP_PORT = 3000;
LANDING_PAGE = "explore";
};
service.DISABLE_REGISTRATION = true;
security.INSTALL_LOCK = true;
cache = {
ADAPTER = "redis";
HOST = "redis://127.0.0.1:6380/0?pool_size=100&idle_timeout=180s";
ITEM_TTL = "16h";
};
"cache.last_commit" = {
ITEM_TTL = "8760h";
COMMITS_COUNT = 100;
};
session = {
PROVIDER = "redis";
PROVIDER_CONFIG = "redis://127.0.0.1:6380/1?pool_size=100&idle_timeout=180s";
COOKIE_SECURE = true;
SAME_SITE = "strict";
};
api.ENABLE_SWAGGER = false;
};
};
services.litestream = {
enable = true;
environmentFile = config.sops.secrets.michael-gitea-litestream.path;
settings.dbs = [
{
path = "/var/lib/gitea/data/gitea.db";
replicas = [
{
type = "s3";
bucket = "michael-gitea-litestream";
path = "gitea";
endpoint = "s3.eu-central-003.backblazeb2.com";
}
];
}
];
};
systemd.services.litestream.serviceConfig = {
User = lib.mkForce "gitea";
Group = lib.mkForce "gitea";
};
services.caddy = {
enable = true;
virtualHosts."git.schmatzler.com".extraConfig = ''
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
}
reverse_proxy localhost:3000
'';
};
services.restic.backups.gitea = {
repository = "s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories";
paths = ["/var/lib/gitea"];
exclude = [
"/var/lib/gitea/log"
"/var/lib/gitea/data/gitea.db"
"/var/lib/gitea/data/gitea.db-shm"
"/var/lib/gitea/data/gitea.db-wal"
];
passwordFile = config.sops.secrets.michael-gitea-restic-password.path;
environmentFile = config.sops.secrets.michael-gitea-restic-env.path;
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 6"
];
timerConfig = {
OnCalendar = "daily";
Persistent = true;
RandomizedDelaySec = "1h";
};
};
systemd.services.restic-backups-gitea = {
wants = ["restic-init-gitea.service"];
after = ["restic-init-gitea.service"];
serviceConfig = {
User = lib.mkForce "gitea";
Group = lib.mkForce "gitea";
};
};
systemd.services.restic-init-gitea = {
description = "Initialize Restic repository for Gitea backups";
wantedBy = ["multi-user.target"];
after = ["network-online.target"];
wants = ["network-online.target"];
path = [pkgs.restic];
serviceConfig = {
Type = "oneshot";
User = "gitea";
Group = "gitea";
RemainAfterExit = true;
EnvironmentFile = config.sops.secrets.michael-gitea-restic-env.path;
};
script = ''
export RESTIC_PASSWORD=$(cat ${config.sops.secrets.michael-gitea-restic-password.path})
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories snapshots &>/dev/null || \
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories init
'';
};
};
}

View File

@@ -1,58 +0,0 @@
{
config,
lib,
pkgs,
...
}: {
services.restic.backups.gitea = {
repository = "s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories";
paths = ["/var/lib/gitea"];
exclude = [
"/var/lib/gitea/log"
"/var/lib/gitea/data/gitea.db"
"/var/lib/gitea/data/gitea.db-shm"
"/var/lib/gitea/data/gitea.db-wal"
];
passwordFile = config.sops.secrets.michael-gitea-restic-password.path;
environmentFile = config.sops.secrets.michael-gitea-restic-env.path;
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 4"
"--keep-monthly 6"
];
timerConfig = {
OnCalendar = "daily";
Persistent = true;
RandomizedDelaySec = "1h";
};
};
systemd.services.restic-backups-gitea = {
wants = ["restic-init-gitea.service"];
after = ["restic-init-gitea.service"];
serviceConfig = {
User = lib.mkForce "gitea";
Group = lib.mkForce "gitea";
};
};
systemd.services.restic-init-gitea = {
description = "Initialize Restic repository for Gitea backups";
wantedBy = ["multi-user.target"];
after = ["network-online.target"];
wants = ["network-online.target"];
path = [pkgs.restic];
serviceConfig = {
Type = "oneshot";
User = "gitea";
Group = "gitea";
RemainAfterExit = true;
EnvironmentFile = config.sops.secrets.michael-gitea-restic-env.path;
};
script = ''
export RESTIC_PASSWORD=$(cat ${config.sops.secrets.michael-gitea-restic-password.path})
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories snapshots &>/dev/null || \
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories init
'';
};
}

View File

@@ -1,114 +0,0 @@
{
config,
lib,
...
}: {
sops.secrets = {
michael-gitea-litestream = {
sopsFile = ../../../../secrets/michael-gitea-litestream;
format = "binary";
owner = "gitea";
group = "gitea";
path = "/run/secrets/michael-gitea-litestream";
};
michael-gitea-restic-password = {
sopsFile = ../../../../secrets/michael-gitea-restic-password;
format = "binary";
owner = "gitea";
group = "gitea";
path = "/run/secrets/michael-gitea-restic-password";
};
michael-gitea-restic-env = {
sopsFile = ../../../../secrets/michael-gitea-restic-env;
format = "binary";
owner = "gitea";
group = "gitea";
path = "/run/secrets/michael-gitea-restic-env";
};
};
networking.firewall.allowedTCPPorts = [80 443];
services.redis.servers.gitea = {
enable = true;
port = 6380;
bind = "127.0.0.1";
settings = {
maxmemory = "64mb";
maxmemory-policy = "allkeys-lru";
};
};
services.gitea = {
enable = true;
database = {
type = "sqlite3";
path = "/var/lib/gitea/data/gitea.db";
};
settings = {
server = {
ROOT_URL = "https://git.schmatzler.com/";
DOMAIN = "git.schmatzler.com";
HTTP_ADDR = "127.0.0.1";
HTTP_PORT = 3000;
LANDING_PAGE = "explore";
};
service.DISABLE_REGISTRATION = true;
security.INSTALL_LOCK = true;
cache = {
ADAPTER = "redis";
HOST = "redis://127.0.0.1:6380/0?pool_size=100&idle_timeout=180s";
ITEM_TTL = "16h";
};
"cache.last_commit" = {
ITEM_TTL = "8760h";
COMMITS_COUNT = 100;
};
session = {
PROVIDER = "redis";
PROVIDER_CONFIG = "redis://127.0.0.1:6380/1?pool_size=100&idle_timeout=180s";
COOKIE_SECURE = true;
SAME_SITE = "strict";
};
api.ENABLE_SWAGGER = false;
};
};
services.litestream = {
enable = true;
environmentFile = config.sops.secrets.michael-gitea-litestream.path;
settings = {
dbs = [
{
path = "/var/lib/gitea/data/gitea.db";
replicas = [
{
type = "s3";
bucket = "michael-gitea-litestream";
path = "gitea";
endpoint = "s3.eu-central-003.backblazeb2.com";
}
];
}
];
};
};
systemd.services.litestream.serviceConfig = {
User = lib.mkForce "gitea";
Group = lib.mkForce "gitea";
};
services.caddy = {
enable = true;
virtualHosts."git.schmatzler.com".extraConfig = ''
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
}
reverse_proxy localhost:3000
'';
};
}

View File

@@ -1,69 +0,0 @@
{config, ...}: {
services.adguardhome = {
enable = true;
host = "127.0.0.1";
port = 10000;
settings = {
dhcp = {
enabled = false;
};
dns = {
upstream_dns = [
"1.1.1.1"
"1.0.0.1"
];
};
filtering = {
protection_enabled = true;
filtering_enabled = true;
safe_search = {
enabled = false;
};
safebrowsing_enabled = true;
blocked_response_ttl = 10;
filters_update_interval = 24;
blocked_services = {
ids = [
"reddit"
"twitter"
];
};
};
filters = [
{
enabled = true;
url = "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/adblock/pro.txt";
name = "HaGeZi Multi PRO";
id = 1;
}
{
enabled = true;
url = "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/adblock/tif.txt";
name = "HaGeZi Threat Intelligence Feeds";
id = 2;
}
{
enabled = true;
url = "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/adblock/gambling.txt";
name = "HaGeZi Gambling";
id = 3;
}
{
enabled = true;
url = "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/adblock/nsfw.txt";
name = "HaGeZi NSFW";
id = 4;
}
];
};
};
services.caddy.virtualHosts."adguard.manticore-hippocampus.ts.net" = {
extraConfig = ''
tls {
get_certificate tailscale
}
reverse_proxy localhost:${toString config.services.adguardhome.port}
'';
};
}

View File

@@ -1,10 +0,0 @@
{...}: {
services.caddy.virtualHosts."cache.manticore-hippocampus.ts.net" = {
extraConfig = ''
tls {
get_certificate tailscale
}
reverse_proxy localhost:32843
'';
};
}

View File

@@ -1,128 +0,0 @@
{
config,
inputs',
pkgs,
...
}: let
homeDir = "/home/cschmatzler";
notabilityScripts = ./notability;
dataRoot = "${homeDir}/.local/share/notability-ingest";
stateRoot = "${homeDir}/.local/state/notability-ingest";
notesRoot = "${homeDir}/Notes";
webdavRoot = "${dataRoot}/webdav-root";
userPackages = with pkgs; [
qmd
poppler-utils
rclone
sqlite
zk
];
commonPath = with pkgs;
[
inputs'.llm-agents.packages.pi
coreutils
inotify-tools
nushell
util-linux
]
++ userPackages;
commonEnvironment = {
HOME = homeDir;
NOTABILITY_ARCHIVE_ROOT = "${dataRoot}/archive";
NOTABILITY_DATA_ROOT = dataRoot;
NOTABILITY_DB_PATH = "${stateRoot}/db.sqlite";
NOTABILITY_NOTES_DIR = notesRoot;
NOTABILITY_RENDER_ROOT = "${dataRoot}/rendered-pages";
NOTABILITY_SESSIONS_ROOT = "${stateRoot}/sessions";
NOTABILITY_STATE_ROOT = stateRoot;
NOTABILITY_TRANSCRIPT_ROOT = "${stateRoot}/transcripts";
NOTABILITY_WEBDAV_ROOT = webdavRoot;
XDG_CONFIG_HOME = "${homeDir}/.config";
};
mkTmpDirRule = path: "d ${path} 0755 cschmatzler users -";
mkNotabilityService = {
description,
script,
after ? [],
requires ? [],
environment ? {},
}: {
inherit after description requires;
wantedBy = ["multi-user.target"];
path = commonPath;
environment = commonEnvironment // environment;
serviceConfig = {
ExecStart = "${pkgs.nushell}/bin/nu ${notabilityScripts}/${script}";
Group = "users";
Restart = "always";
RestartSec = 5;
User = "cschmatzler";
WorkingDirectory = homeDir;
};
};
in {
sops.secrets.tahani-notability-webdav-password = {
sopsFile = ../../../../secrets/tahani-notability-webdav-password;
format = "binary";
owner = "cschmatzler";
path = "/run/secrets/tahani-notability-webdav-password";
};
home-manager.users.cschmatzler = {
home.packages = userPackages;
home.file.".config/qmd/index.yml".text = ''
collections:
notes:
path: ${notesRoot}
pattern: "**/*.md"
'';
};
systemd.tmpfiles.rules =
builtins.map mkTmpDirRule [
notesRoot
dataRoot
webdavRoot
"${dataRoot}/archive"
"${dataRoot}/rendered-pages"
stateRoot
"${stateRoot}/jobs"
"${stateRoot}/jobs/queued"
"${stateRoot}/jobs/running"
"${stateRoot}/jobs/failed"
"${stateRoot}/jobs/done"
"${stateRoot}/jobs/results"
"${stateRoot}/sessions"
"${stateRoot}/transcripts"
];
services.caddy.virtualHosts."tahani.manticore-hippocampus.ts.net".extraConfig = ''
tls {
get_certificate tailscale
}
handle /notability* {
reverse_proxy 127.0.0.1:9980
}
'';
systemd.services.notability-webdav =
mkNotabilityService {
description = "Notability WebDAV landing zone";
script = "webdav.nu";
after = ["network.target"];
environment = {
NOTABILITY_WEBDAV_ADDR = "127.0.0.1:9980";
NOTABILITY_WEBDAV_BASEURL = "/notability";
NOTABILITY_WEBDAV_PASSWORD_FILE = config.sops.secrets.tahani-notability-webdav-password.path;
NOTABILITY_WEBDAV_USER = "notability";
};
};
systemd.services.notability-watch =
mkNotabilityService {
description = "Watch and ingest Notability WebDAV uploads";
script = "watch.nu";
after = ["notability-webdav.service"];
requires = ["notability-webdav.service"];
};
}

View File

@@ -1,87 +0,0 @@
{config, ...}: {
services.caddy = {
enable = true;
enableReload = false;
globalConfig = ''
admin off
'';
virtualHosts."docs.manticore-hippocampus.ts.net" = {
extraConfig = ''
tls {
get_certificate tailscale
}
reverse_proxy localhost:${toString config.services.paperless.port}
'';
};
virtualHosts."docs-ai.manticore-hippocampus.ts.net" = {
extraConfig = ''
tls {
get_certificate tailscale
}
reverse_proxy localhost:8081
'';
};
};
virtualisation.oci-containers = {
backend = "docker";
containers.paperless-gpt = {
image = "icereed/paperless-gpt:latest";
autoStart = true;
ports = [
"127.0.0.1:8081:8080"
];
volumes = [
"paperless-gpt-data:/app/data"
"paperless-gpt-prompts:/app/prompts"
"${./paperless-gpt-prompts/tag_prompt.tmpl}:/app/prompts/tag_prompt.tmpl:ro"
"${./paperless-gpt-prompts/title_prompt.tmpl}:/app/prompts/title_prompt.tmpl:ro"
];
environment = {
PAPERLESS_BASE_URL = "http://host.docker.internal:${toString config.services.paperless.port}";
LLM_PROVIDER = "openai";
LLM_MODEL = "gpt-5.4";
LLM_LANGUAGE = "German";
VISION_LLM_PROVIDER = "openai";
VISION_LLM_MODEL = "gpt-5.4";
LOG_LEVEL = "info";
};
environmentFiles = [
config.sops.secrets.tahani-paperless-gpt-env.path
];
extraOptions = [
"--add-host=host.docker.internal:host-gateway"
];
};
};
services.redis.servers.paperless = {
enable = true;
port = 6379;
bind = "127.0.0.1";
settings = {
maxmemory = "256mb";
maxmemory-policy = "allkeys-lru";
};
};
services.paperless = {
enable = true;
address = "0.0.0.0";
consumptionDir = "/var/lib/paperless/consume";
passwordFile = config.sops.secrets.tahani-paperless-password.path;
settings = {
PAPERLESS_DBENGINE = "sqlite";
PAPERLESS_REDIS = "redis://127.0.0.1:6379";
PAPERLESS_CONSUMER_IGNORE_PATTERN = [
".DS_STORE/*"
"desktop.ini"
];
PAPERLESS_CONSUMER_POLLING = 30;
PAPERLESS_CONSUMER_RECURSIVE = true;
PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS = true;
PAPERLESS_OCR_LANGUAGE = "deu+eng";
PAPERLESS_CSRF_TRUSTED_ORIGINS = "https://docs.manticore-hippocampus.ts.net";
};
};
}

View File

@@ -1,33 +1,34 @@
{den, ...}: {
den.hosts.aarch64-darwin.chidi.users.cschmatzler.aspect = "chidi-cschmatzler";
den.aspects.chidi-cschmatzler = {
{
den,
lib,
...
}: let
hostLib = import ../_lib/hosts.nix {inherit den lib;};
local = import ../_lib/local.nix;
host = "chidi";
hostMeta = local.hosts.chidi;
in
hostLib.mkUserHost {
system = hostMeta.system;
inherit host;
user = local.user.name;
includes = [den.aspects.user-darwin-laptop];
homeManager = {...}: {
programs.git.settings.user.email = "christoph@tuist.dev";
programs.git.settings.user.email = local.user.emails.work;
};
};
}
// hostLib.mkPerHostAspect {
inherit host;
includes = [
den.aspects.host-darwin-base
den.aspects.opencode-api-key
];
darwin = {...}: {
networking.hostName = host;
networking.computerName = host;
den.aspects.chidi.includes = [
(den.lib.perHost {
includes = [den.aspects.host-darwin-base];
darwin = {...}: {
networking.hostName = "chidi";
networking.computerName = "chidi";
sops.secrets.opencode-api-key = {
sopsFile = ../../secrets/opencode-api-key;
format = "binary";
owner = "cschmatzler";
path = "/run/secrets/opencode-api-key";
};
homebrew.casks = [
"slack"
];
};
})
];
}
homebrew.casks = [
"slack"
];
};
}

View File

@@ -1,28 +1,30 @@
{den, ...}: {
den.hosts.aarch64-darwin.janet.users.cschmatzler.aspect = "janet-cschmatzler";
den.aspects.janet-cschmatzler = {
{
den,
lib,
...
}: let
hostLib = import ../_lib/hosts.nix {inherit den lib;};
local = import ../_lib/local.nix;
host = "janet";
hostMeta = local.hosts.janet;
in
hostLib.mkUserHost {
system = hostMeta.system;
inherit host;
user = local.user.name;
includes = [
den.aspects.user-darwin-laptop
den.aspects.user-personal
];
};
den.aspects.janet.includes = [
(den.lib.perHost {
includes = [den.aspects.host-darwin-base];
darwin = {...}: {
networking.hostName = "janet";
networking.computerName = "janet";
sops.secrets.opencode-api-key = {
sopsFile = ../../secrets/opencode-api-key;
format = "binary";
owner = "cschmatzler";
path = "/run/secrets/opencode-api-key";
};
};
})
];
}
}
// hostLib.mkPerHostAspect {
inherit host;
includes = [
den.aspects.host-darwin-base
den.aspects.opencode-api-key
];
darwin = {...}: {
networking.hostName = host;
networking.computerName = host;
};
}

View File

@@ -1,30 +1,34 @@
{
den,
inputs,
lib,
...
}: {
den.hosts.x86_64-linux.michael.users.cschmatzler.aspect = "michael-cschmatzler";
den.aspects.michael-cschmatzler = {
}: let
hostLib = import ../_lib/hosts.nix {inherit den lib;};
local = import ../_lib/local.nix;
host = "michael";
hostMeta = local.hosts.michael;
in
hostLib.mkUserHost {
system = hostMeta.system;
inherit host;
user = local.user.name;
includes = [den.aspects.user-minimal];
};
}
// hostLib.mkPerHostAspect {
inherit host;
includes = [
den.aspects.host-public-server
den.aspects.gitea
];
nixos = {modulesPath, ...}: {
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
./_parts/michael/disk-config.nix
./_parts/michael/hardware-configuration.nix
inputs.disko.nixosModules.default
];
den.aspects.michael.includes = [
(den.lib.perHost {
includes = [den.aspects.host-public-server];
nixos = {modulesPath, ...}: {
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
./_parts/michael/backups.nix
./_parts/michael/disk-config.nix
./_parts/michael/gitea.nix
./_parts/michael/hardware-configuration.nix
inputs.disko.nixosModules.default
];
networking.hostName = "michael";
};
})
];
}
networking.hostName = host;
};
}

View File

@@ -1,13 +1,23 @@
{den, ...}: {
den.hosts.x86_64-linux.tahani.users.cschmatzler.aspect = "tahani-cschmatzler";
den.aspects.tahani-cschmatzler = {
{
den,
lib,
...
}: let
hostLib = import ../_lib/hosts.nix {inherit den lib;};
local = import ../_lib/local.nix;
secretLib = import ../_lib/secrets.nix {inherit lib;};
host = "tahani";
hostMeta = local.hosts.tahani;
in
hostLib.mkUserHost {
system = hostMeta.system;
inherit host;
user = local.user.name;
includes = [
den.aspects.user-workstation
den.aspects.user-personal
den.aspects.email
];
homeManager = {
programs.nushell.extraConfig = ''
if $nu.is-interactive and ('SSH_CONNECTION' in ($env | columns)) and ('ZELLIJ' not-in ($env | columns)) {
@@ -20,61 +30,45 @@
}
'';
};
};
}
// hostLib.mkPerHostAspect {
inherit host;
includes = [
den.aspects.host-nixos-base
den.aspects.opencode-api-key
den.aspects.adguardhome
den.aspects.cache
den.aspects.notability
den.aspects.paperless
];
nixos = {...}: {
imports = [
./_parts/tahani/networking.nix
];
den.aspects.tahani.includes = [
(den.lib.perHost {
includes = [den.aspects.host-nixos-base];
networking.hostName = host;
nixos = {...}: {
imports = [
./_parts/tahani/adguardhome.nix
./_parts/tahani/cache.nix
./_parts/tahani/networking.nix
./_parts/tahani/notability.nix
./_parts/tahani/paperless.nix
];
networking.hostName = "tahani";
sops.secrets = {
opencode-api-key = {
sopsFile = ../../secrets/opencode-api-key;
format = "binary";
owner = "cschmatzler";
path = "/run/secrets/opencode-api-key";
};
tahani-paperless-password = {
sopsFile = ../../secrets/tahani-paperless-password;
format = "binary";
path = "/run/secrets/tahani-paperless-password";
};
tahani-paperless-gpt-env = {
sopsFile = ../../secrets/tahani-paperless-gpt-env;
format = "binary";
path = "/run/secrets/tahani-paperless-gpt-env";
};
tahani-email-password = {
sopsFile = ../../secrets/tahani-email-password;
format = "binary";
owner = "cschmatzler";
path = "/run/secrets/tahani-email-password";
};
};
virtualisation.docker.enable = true;
users.users.cschmatzler.extraGroups = ["docker" "paperless"];
systemd.tmpfiles.rules = [
"d /var/lib/paperless/consume 2775 paperless paperless -"
"d /var/lib/paperless/consume/inbox-triage 2775 paperless paperless -"
];
swapDevices = [
{
device = "/swapfile";
size = 16 * 1024;
}
];
sops.secrets.tahani-email-password =
secretLib.mkUserBinarySecret {
name = "tahani-email-password";
sopsFile = ../../secrets/tahani-email-password;
};
})
];
}
virtualisation.docker.enable = true;
users.users.${local.user.name}.extraGroups = [
"docker"
"paperless"
];
systemd.tmpfiles.rules = [
"d /var/lib/paperless/consume 2775 paperless paperless -"
"d /var/lib/paperless/consume/inbox-triage 2775 paperless paperless -"
];
swapDevices = [
{
device = "/swapfile";
size = 16 * 1024;
}
];
};
}

View File

@@ -1,6 +1,10 @@
{...}: {
den.hosts.aarch64-darwin.chidi.users.cschmatzler = {};
den.hosts.aarch64-darwin.janet.users.cschmatzler = {};
den.hosts.x86_64-linux.michael.users.cschmatzler = {};
den.hosts.x86_64-linux.tahani.users.cschmatzler = {};
}
{lib, ...}: let
local = import ./_lib/local.nix;
in
lib.foldl' lib.recursiveUpdate {} (
lib.mapAttrsToList (
host: hostMeta:
lib.setAttrByPath ["den" "hosts" hostMeta.system host "users" local.user.name] {}
)
local.hosts
)

View File

@@ -21,24 +21,20 @@
overalljails = true;
};
jails = {
sshd = {
settings = {
enabled = true;
port = "ssh";
filter = "sshd";
maxretry = 3;
};
sshd.settings = {
enabled = true;
port = "ssh";
filter = "sshd";
maxretry = 3;
};
gitea = {
settings = {
enabled = true;
filter = "gitea";
logpath = "/var/lib/gitea/log/gitea.log";
maxretry = 10;
findtime = 3600;
bantime = 900;
action = "iptables-allports";
};
gitea.settings = {
enabled = true;
filter = "gitea";
logpath = "/var/lib/gitea/log/gitea.log";
maxretry = 10;
findtime = 3600;
bantime = 900;
action = "iptables-allports";
};
};
};
@@ -60,23 +56,6 @@
};
den.aspects.tailscale.darwin = {
services.tailscale = {
enable = true;
};
};
# Network tools
den.aspects.network.homeManager = {
pkgs,
lib,
...
}: {
home.packages = with pkgs;
[
dig
]
++ lib.optionals stdenv.isDarwin [
tailscale
];
services.tailscale.enable = true;
};
}

View File

@@ -1,11 +1,14 @@
{inputs, ...}: {
{inputs, ...}: let
local = import ./_lib/local.nix;
userHome = local.mkHome local.hosts.michael.system;
in {
den.aspects.nixos-system.nixos = {pkgs, ...}: {
imports = [inputs.home-manager.nixosModules.home-manager];
security.sudo.enable = true;
security.sudo.extraRules = [
{
users = ["cschmatzler"];
users = [local.user.name];
commands = [
{
command = "/run/current-system/sw/bin/nix-env";
@@ -46,9 +49,9 @@
time.timeZone = "UTC";
nix = {
settings.trusted-users = ["cschmatzler"];
settings.trusted-users = [local.user.name];
gc.dates = "weekly";
nixPath = ["nixos-config=/home/cschmatzler/.local/share/src/nixos-config:/etc/nixos"];
nixPath = ["nixos-config=${userHome}/.local/share/src/nixos-config:/etc/nixos"];
};
boot = {
@@ -71,9 +74,9 @@
};
users.users = {
cschmatzler = {
${local.user.name} = {
isNormalUser = true;
home = "/home/cschmatzler";
home = userHome;
extraGroups = [
"wheel"
"sudo"
@@ -93,7 +96,5 @@
];
};
};
home-manager.useGlobalPkgs = true;
};
}

136
modules/notability.nix Normal file
View File

@@ -0,0 +1,136 @@
{lib, ...}: let
caddyLib = import ./_lib/caddy.nix;
local = import ./_lib/local.nix;
secretLib = import ./_lib/secrets.nix {inherit lib;};
inherit (local) user;
notabilityScripts = ./_notability;
tahani = local.hosts.tahani;
in {
den.aspects.notability.nixos = {
config,
inputs',
pkgs,
...
}: let
homeDir = tahani.home;
dataRoot = "${homeDir}/.local/share/notability-ingest";
stateRoot = "${homeDir}/.local/state/notability-ingest";
notesRoot = "${homeDir}/Notes";
webdavRoot = "${dataRoot}/webdav-root";
userPackages = with pkgs; [
qmd
poppler-utils
rclone
sqlite
zk
];
commonPath = with pkgs;
[
inputs'.llm-agents.packages.pi
coreutils
inotify-tools
nushell
util-linux
]
++ userPackages;
commonEnvironment = {
HOME = homeDir;
NOTABILITY_ARCHIVE_ROOT = "${dataRoot}/archive";
NOTABILITY_DATA_ROOT = dataRoot;
NOTABILITY_DB_PATH = "${stateRoot}/db.sqlite";
NOTABILITY_NOTES_DIR = notesRoot;
NOTABILITY_RENDER_ROOT = "${dataRoot}/rendered-pages";
NOTABILITY_SESSIONS_ROOT = "${stateRoot}/sessions";
NOTABILITY_STATE_ROOT = stateRoot;
NOTABILITY_TRANSCRIPT_ROOT = "${stateRoot}/transcripts";
NOTABILITY_WEBDAV_ROOT = webdavRoot;
XDG_CONFIG_HOME = "${homeDir}/.config";
};
mkTmpDirRule = path: "d ${path} 0755 ${user.name} users -";
mkNotabilityService = {
description,
script,
after ? [],
requires ? [],
environment ? {},
}: {
inherit after description requires;
wantedBy = ["multi-user.target"];
path = commonPath;
environment = commonEnvironment // environment;
serviceConfig = {
ExecStart = "${pkgs.nushell}/bin/nu ${notabilityScripts}/${script}";
Group = "users";
Restart = "always";
RestartSec = 5;
User = user.name;
WorkingDirectory = homeDir;
};
};
in {
sops.secrets.tahani-notability-webdav-password =
secretLib.mkUserBinarySecret {
name = "tahani-notability-webdav-password";
sopsFile = ../secrets/tahani-notability-webdav-password;
};
home-manager.users.${user.name} = {
home.packages = userPackages;
home.file.".config/qmd/index.yml".text = ''
collections:
notes:
path: ${notesRoot}
pattern: "**/*.md"
'';
};
systemd.tmpfiles.rules =
builtins.map mkTmpDirRule [
notesRoot
dataRoot
webdavRoot
"${dataRoot}/archive"
"${dataRoot}/rendered-pages"
stateRoot
"${stateRoot}/jobs"
"${stateRoot}/jobs/queued"
"${stateRoot}/jobs/running"
"${stateRoot}/jobs/failed"
"${stateRoot}/jobs/done"
"${stateRoot}/jobs/results"
"${stateRoot}/sessions"
"${stateRoot}/transcripts"
];
services.caddy.virtualHosts =
caddyLib.mkTailscaleVHost {
name = "tahani";
configText = ''
handle /notability* {
reverse_proxy 127.0.0.1:9980
}
'';
};
systemd.services.notability-webdav =
mkNotabilityService {
description = "Notability WebDAV landing zone";
script = "webdav.nu";
after = ["network.target"];
environment = {
NOTABILITY_WEBDAV_ADDR = "127.0.0.1:9980";
NOTABILITY_WEBDAV_BASEURL = "/notability";
NOTABILITY_WEBDAV_PASSWORD_FILE = config.sops.secrets.tahani-notability-webdav-password.path;
NOTABILITY_WEBDAV_USER = "notability";
};
};
systemd.services.notability-watch =
mkNotabilityService {
description = "Watch and ingest Notability WebDAV uploads";
script = "watch.nu";
after = ["notability-webdav.service"];
requires = ["notability-webdav.service"];
};
};
}

11
modules/opencode.nix Normal file
View File

@@ -0,0 +1,11 @@
{lib, ...}: let
secretLib = import ./_lib/secrets.nix {inherit lib;};
in {
den.aspects.opencode-api-key.os = {
sops.secrets.opencode-api-key =
secretLib.mkUserBinarySecret {
name = "opencode-api-key";
sopsFile = ../secrets/opencode-api-key;
};
};
}

100
modules/paperless.nix Normal file
View File

@@ -0,0 +1,100 @@
{lib, ...}: let
caddyLib = import ./_lib/caddy.nix;
local = import ./_lib/local.nix;
secretLib = import ./_lib/secrets.nix {inherit lib;};
paperlessPrompts = ./_paperless;
in {
den.aspects.paperless.nixos = {config, ...}: {
sops.secrets = {
tahani-paperless-password =
secretLib.mkBinarySecret {
name = "tahani-paperless-password";
sopsFile = ../secrets/tahani-paperless-password;
};
tahani-paperless-gpt-env =
secretLib.mkBinarySecret {
name = "tahani-paperless-gpt-env";
sopsFile = ../secrets/tahani-paperless-gpt-env;
};
};
services.caddy = {
enable = true;
enableReload = false;
globalConfig = ''
admin off
'';
virtualHosts =
caddyLib.mkTailscaleVHost {
name = "docs";
configText = "reverse_proxy localhost:${toString config.services.paperless.port}";
}
// caddyLib.mkTailscaleVHost {
name = "docs-ai";
configText = "reverse_proxy localhost:8081";
};
};
virtualisation.oci-containers = {
backend = "docker";
containers.paperless-gpt = {
image = "icereed/paperless-gpt:latest";
autoStart = true;
ports = [
"127.0.0.1:8081:8080"
];
volumes = [
"paperless-gpt-data:/app/data"
"paperless-gpt-prompts:/app/prompts"
"${paperlessPrompts}/tag_prompt.tmpl:/app/prompts/tag_prompt.tmpl:ro"
"${paperlessPrompts}/title_prompt.tmpl:/app/prompts/title_prompt.tmpl:ro"
];
environment = {
PAPERLESS_BASE_URL = "http://host.docker.internal:${toString config.services.paperless.port}";
LLM_PROVIDER = "openai";
LLM_MODEL = "gpt-5.4";
LLM_LANGUAGE = "German";
VISION_LLM_PROVIDER = "openai";
VISION_LLM_MODEL = "gpt-5.4";
LOG_LEVEL = "info";
};
environmentFiles = [
config.sops.secrets.tahani-paperless-gpt-env.path
];
extraOptions = [
"--add-host=host.docker.internal:host-gateway"
];
};
};
services.redis.servers.paperless = {
enable = true;
port = 6379;
bind = "127.0.0.1";
settings = {
maxmemory = "256mb";
maxmemory-policy = "allkeys-lru";
};
};
services.paperless = {
enable = true;
address = "0.0.0.0";
consumptionDir = "/var/lib/paperless/consume";
passwordFile = config.sops.secrets.tahani-paperless-password.path;
settings = {
PAPERLESS_DBENGINE = "sqlite";
PAPERLESS_REDIS = "redis://127.0.0.1:6379";
PAPERLESS_CONSUMER_IGNORE_PATTERN = [
".DS_STORE/*"
"desktop.ini"
];
PAPERLESS_CONSUMER_POLLING = 30;
PAPERLESS_CONSUMER_RECURSIVE = true;
PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS = true;
PAPERLESS_OCR_LANGUAGE = "deu+eng";
PAPERLESS_CSRF_TRUSTED_ORIGINS = "https://${local.tailscaleHost "docs"}";
};
};
};
}

View File

@@ -1,17 +1,11 @@
{den, ...}: {
den.aspects.user-base = {
includes = [
den.aspects.shell
den.aspects.ssh-client
den.aspects.terminal
den.aspects.atuin
den.aspects.secrets
den.aspects.zellij
den.aspects.zk
];
homeManager = {
programs.home-manager.enable = true;
};
};
den.aspects.user-base.includes = [
den.aspects.shell
den.aspects.ssh-client
den.aspects.terminal
den.aspects.atuin
den.aspects.secrets
den.aspects.zellij
den.aspects.zk
];
}

View File

@@ -1,11 +1,5 @@
{den, ...}: {
den.aspects.user-minimal = {
includes = [
den.aspects.shell
];
homeManager = {
programs.home-manager.enable = true;
};
};
den.aspects.user-minimal.includes = [
den.aspects.shell
];
}

View File

@@ -1,5 +1,7 @@
{...}: {
{...}: let
local = import ../../_lib/local.nix;
in {
den.aspects.user-personal.homeManager = {
programs.git.settings.user.email = "christoph@schmatzler.com";
programs.git.settings.user.email = local.user.emails.personal;
};
}

View File

@@ -1,4 +1,6 @@
{inputs, ...}: {
{inputs, ...}: let
local = import ./_lib/local.nix;
in {
# Import sops-nix modules into den.default per-class
den.default.nixos.imports = [inputs.sops-nix.nixosModules.sops];
den.default.darwin.imports = [inputs.sops-nix.darwinModules.sops];
@@ -8,7 +10,7 @@
# Configure Darwin SOPS defaults
den.default.darwin = {
sops.age.keyFile = "/Users/cschmatzler/.config/sops/age/keys.txt";
sops.age.keyFile = "${local.mkHome local.hosts.chidi.system}/.config/sops/age/keys.txt";
sops.age.sshKeyPaths = [];
sops.gnupg.sshKeyPaths = [];
};

View File

@@ -268,9 +268,11 @@
git_state = {
disabled = true;
};
custom.scm = {
custom.scm = let
local = import ./_lib/local.nix;
in {
when = "jj-starship detect";
shell = ["jj-starship" "--strip-bookmark-prefix" "cschmatzler/" "--truncate-name" "20" "--bookmarks-display-limit" "1"];
shell = ["jj-starship" "--strip-bookmark-prefix" "${local.user.name}/" "--truncate-name" "20" "--bookmarks-display-limit" "1"];
format = "$output ";
};
lua = {