Compare commits

...

13 commits

25 changed files with 449 additions and 89 deletions

View file

@ -57,13 +57,11 @@ nix multi user, multi system, configuration with `sops` secret management, `home
- auto turn off on power loss - nut
- zfs email after scrubbing # TODO: test this
- SMART test with email results
- fix nfs
- samba mounts
- offline access for nfs mounts (overlay with rsync might be a good option here? https://www.spinics.net/lists/linux-unionfs/msg07105.html note about nfs4 and overlay fs)
- Create Tor guard/relay server
- migrate away from flakes and move to npins
- whisper
- nix mcp
- zfs encryption FIDO2 2fa (look into shavee)
- Secure Boot - https://github.com/nix-community/lanzaboote
- rotate sops encryption keys periodically (and somehow sync between devices?)

View file

@ -18,9 +18,7 @@ in {
home.packages = lib.lists.optionals userConfig.isDesktopUser (
with pkgs; [
ungoogled-chromium
krita
gnomeExtensions.dash-to-panel
(lib.mkIf hardware.piperMouse.enable piper)
]
);
@ -61,6 +59,8 @@ in {
makemkv.enable = true;
signal-desktop-bin.enable = true;
steam.enable = true;
piper.enable = hardware.piperMouse.enable;
krita.enable = true;
})
];
};

View file

@ -36,6 +36,7 @@ in {
protonvpn-gui.enable = true;
dbeaver-bin.enable = true;
bruno.enable = true;
piper.enable = hardware.piperMouse.enable;
})
(lib.mkIf (hardware.directAccess.enable && config.user.isDesktopUser) {
anki.enable = true;
@ -48,6 +49,7 @@ in {
vscode.enable = true;
firefox.enable = true;
steam.enable = true;
krita.enable = true;
})
];
}
@ -76,7 +78,6 @@ in {
libreoffice
inkscape
gimp
krita
freecad
# cura
# kicad-small
@ -105,7 +106,6 @@ in {
noisetorch
# hardware management tools
(lib.mkIf hardware.piperMouse.enable piper)
(lib.mkIf hardware.openRGB.enable openrgb)
(lib.mkIf hardware.viaKeyboard.enable via)

View file

@ -50,6 +50,7 @@ in {
tauriVscode.enable = true;
vscodeEslint.enable = true;
vscodeJest.enable = true;
vitest.enable = true;
vscodeStandard.enable = true;
vscodeStylelint.enable = true;
@ -67,7 +68,13 @@ in {
go.enable = true;
# claude development
claudeDev.enable = ai-tooling-enabled;
claudeDev = lib.mkIf ai-tooling-enabled {
enable = true;
mcp = {
nixos.enable = true;
eslint.enable = true;
};
};
# misc extensions
evenBetterToml.enable = true;

View file

@ -296,7 +296,7 @@
extensions = {
sonos.enable = true;
jellyfin.enable = true;
wyoming.enable = true;
wyoming.enable = false; # Temporarily disabled due to dependency conflict in wyoming-piper
};
};

View file

@ -27,7 +27,7 @@
# Enable this if you have graphical corruption issues or application crashes after waking
# up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead
# of just the bare essentials.
powerManagement.enable = false;
powerManagement.enable = true;
# Fine-grained power management. Turns off GPU when not in use.
# Experimental and only works on modern Nvidia GPUs (Turing or newer).

View file

@ -135,6 +135,9 @@
};
};
# Enable network-online.target for better network dependency handling
systemd.services.NetworkManager-wait-online.enable = true;
# Enable touchpad support (enabled default in most desktopManager).
# services.xserver.libinput.enable = true;

View file

@ -3,5 +3,6 @@
imports = [
./configuration.nix
./hardware-configuration.nix
# ./network-mount.nix
];
}

View file

@ -0,0 +1,76 @@
{...}: {
boot.supportedFilesystems = ["nfs"];
fileSystems = {
"/mnt/leyla_documents" = {
device = "defiant:/exports/leyla_documents";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"noatime"
"nofail"
"soft"
"intr" # Allow interruption of NFS calls
"timeo=30" # 3 second timeout (30 deciseconds)
"retrans=2" # Only 2 retries before giving up
"x-systemd.idle-timeout=300" # 5 minute idle timeout for mobile
"x-systemd.device-timeout=15" # 15 second device timeout
"bg" # Background mount - don't block boot
"fsc" # Enable caching
"_netdev" # Network device - wait for network
"x-systemd.requires=network-online.target" # Require network to be online
"x-systemd.after=network-online.target" # Start after network is online
"x-systemd.mount-timeout=30" # 30 second mount timeout
];
};
"/mnt/users_documents" = {
device = "defiant:/exports/users_documents";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"nofail"
"soft"
"intr"
"timeo=30"
"retrans=2"
"x-systemd.idle-timeout=300"
"x-systemd.device-timeout=15"
"bg"
"fsc"
"_netdev"
"x-systemd.requires=network-online.target"
"x-systemd.after=network-online.target"
"x-systemd.mount-timeout=30"
];
};
"/mnt/media" = {
device = "defiant:/exports/media";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"noatime"
"nofail"
"soft"
"intr"
"timeo=30"
"retrans=2"
"x-systemd.idle-timeout=300"
"x-systemd.device-timeout=15"
"bg"
# Mobile-optimized read settings
"rsize=8192" # Smaller read size for mobile
"wsize=8192" # Smaller write size for mobile
"fsc"
"_netdev"
"x-systemd.requires=network-online.target"
"x-systemd.after=network-online.target"
"x-systemd.mount-timeout=30"
];
};
};
}

View file

@ -131,58 +131,8 @@
syncthing.enable = true;
};
boot.supportedFilesystems = ["nfs"];
fileSystems = {
"/mnt/leyla_documents" = {
device = "defiant:/exports/leyla_documents";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"user"
"noatime"
"nofail"
"soft"
"x-systemd.idle-timeout=600"
"fsc"
];
};
"/mnt/users_documents" = {
device = "defiant:/exports/users_documents";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"user"
"nofail"
"soft"
"x-systemd.idle-timeout=600"
"fsc"
];
};
"/mnt/media" = {
device = "defiant:/exports/media";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"user"
"noatime"
"nofail"
"soft"
"x-systemd.idle-timeout=600"
"noatime"
"nodiratime"
"relatime"
"rsize=32768"
"wsize=32768"
"fsc"
];
};
};
# Enable network-online.target for better network dependency handling
systemd.services.NetworkManager-wait-online.enable = true;
environment.systemPackages = with pkgs; [
cachefilesd

View file

@ -4,5 +4,6 @@
./configuration.nix
./hardware-configuration.nix
./nvidia-drivers.nix
# ./network-mount.nix
];
}

View file

@ -0,0 +1,72 @@
{...}: {
boot.supportedFilesystems = ["nfs"];
fileSystems = {
"/mnt/leyla_documents" = {
device = "defiant:/exports/leyla_documents";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"noatime"
"nofail"
"soft"
"intr" # Allow interruption of NFS calls
"timeo=50" # 5 second timeout (50 deciseconds) - longer than mobile
"retrans=3" # 3 retries for desktop
"x-systemd.idle-timeout=600" # 10 minute idle timeout for desktop
"x-systemd.device-timeout=30" # 30 second device timeout
"bg" # Background mount - don't block boot
"fsc" # Enable caching
"_netdev" # Network device - wait for network
"x-systemd.requires=network-online.target" # Require network to be online
"x-systemd.after=network-online.target" # Start after network is online
];
};
"/mnt/users_documents" = {
device = "defiant:/exports/users_documents";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"nofail"
"soft"
"intr"
"timeo=50"
"retrans=3"
"x-systemd.idle-timeout=600"
"bg"
"fsc"
"_netdev"
"x-systemd.requires=network-online.target"
"x-systemd.after=network-online.target"
];
};
"/mnt/media" = {
device = "defiant:/exports/media";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"noatime"
"nofail"
"soft"
"intr"
"timeo=50"
"retrans=3"
"x-systemd.idle-timeout=600"
"x-systemd.device-timeout=30"
"bg"
# Desktop-optimized read settings
"rsize=32768" # Larger read size for desktop
"wsize=32768" # Larger write size for desktop
"fsc"
"_netdev"
"x-systemd.requires=network-online.target"
"x-systemd.after=network-online.target"
];
};
};
}

View file

@ -21,7 +21,7 @@
# Enable this if you have graphical corruption issues or application crashes after waking
# up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead
# of just the bare essentials.
powerManagement.enable = false;
powerManagement.enable = true;
# Fine-grained power management. Turns off GPU when not in use.
# Experimental and only works on modern Nvidia GPUs (Turing or newer).

130
flake.lock generated
View file

@ -1,5 +1,23 @@
{
"nodes": {
"devshell": {
"inputs": {
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1741473158,
"narHash": "sha256-kWNaq6wQUbUMlPgw8Y+9/9wP0F8SHkjy24/mN3UAppg=",
"owner": "numtide",
"repo": "devshell",
"rev": "7c9e793ebe66bcba8292989a68c0419b737a22a0",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"disko": {
"inputs": {
"nixpkgs": [
@ -7,11 +25,11 @@
]
},
"locked": {
"lastModified": 1755519972,
"narHash": "sha256-bU4nqi3IpsUZJeyS8Jk85ytlX61i4b0KCxXX9YcOgVc=",
"lastModified": 1756733629,
"narHash": "sha256-dwWGlDhcO5SMIvMSTB4mjQ5Pvo2vtxvpIknhVnSz2I8=",
"owner": "nix-community",
"repo": "disko",
"rev": "4073ff2f481f9ef3501678ff479ed81402caae6d",
"rev": "a5c4f2ab72e3d1ab43e3e65aa421c6f2bd2e12a1",
"type": "github"
},
"original": {
@ -28,11 +46,11 @@
},
"locked": {
"dir": "pkgs/firefox-addons",
"lastModified": 1755921820,
"narHash": "sha256-xTRXoaGtuIi4VvJNGuHC8DPHnEIJUqVtt7kqU8MdXes=",
"lastModified": 1756699417,
"narHash": "sha256-rpRy5ae5ijEGaK+Cr66NqCQJ6ZeUE5Zi8gUWgKhesto=",
"owner": "rycee",
"repo": "nur-expressions",
"rev": "c43149f02063de9b0d75c2b45f54631bd82667b2",
"rev": "007b803d1eff595d25e7886e83054dbd038bf029",
"type": "gitlab"
},
"original": {
@ -75,6 +93,24 @@
"type": "github"
}
},
"flake-utils_2": {
"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"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
@ -82,11 +118,11 @@
]
},
"locked": {
"lastModified": 1755914636,
"narHash": "sha256-VJ+Gm6YsHlPfUCpmRQxvdiZW7H3YPSrdVOewQHAhZN8=",
"lastModified": 1756734952,
"narHash": "sha256-H6jmduj4QIncLPAPODPSG/8ry9lpr1kRq6fYytU52qU=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "8b55a6ac58b678199e5bba701aaff69e2b3281c0",
"rev": "29ab63bbb3d9eee4a491f7ce701b189becd34068",
"type": "github"
},
"original": {
@ -110,6 +146,28 @@
"type": "github"
}
},
"mcp-nixos": {
"inputs": {
"devshell": "devshell",
"flake-utils": "flake-utils",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1755372538,
"narHash": "sha256-iWhsf1Myk6RyQ7IuNf4bWI3Sqq9pgmhKvEisCXtkxyw=",
"owner": "utensils",
"repo": "mcp-nixos",
"rev": "46b4d4d3d6421bfbadc415532ef74433871e1cda",
"type": "github"
},
"original": {
"owner": "utensils",
"repo": "mcp-nixos",
"type": "github"
}
},
"nix-darwin": {
"inputs": {
"nixpkgs": [
@ -153,17 +211,17 @@
},
"nix-vscode-extensions": {
"inputs": {
"flake-utils": "flake-utils",
"flake-utils": "flake-utils_2",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1755914146,
"narHash": "sha256-ew98ilw4NTodKlILnr3ndsT0Aj9JhqC507JB3efa0pY=",
"lastModified": 1756692643,
"narHash": "sha256-SVos3AYuLvF6bD8Y0b6EiLABoEaiAOa4M/fTCBe0FV8=",
"owner": "nix-community",
"repo": "nix-vscode-extensions",
"rev": "ff42a421ff1d415caa0125e6af6f3bd82e642838",
"rev": "2f1d16db96f1ce8ee3c893ea9dc49c0035846988",
"type": "github"
},
"original": {
@ -174,11 +232,11 @@
},
"nixos-hardware": {
"locked": {
"lastModified": 1755330281,
"narHash": "sha256-aJHFJWP9AuI8jUGzI77LYcSlkA9wJnOIg4ZqftwNGXA=",
"lastModified": 1756245047,
"narHash": "sha256-9bHzrVbjAudbO8q4vYFBWlEkDam31fsz0J7GB8k4AsI=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "3dac8a872557e0ca8c083cdcfc2f218d18e113b0",
"rev": "a65b650d6981e23edd1afa1f01eb942f19cdcbb7",
"type": "github"
},
"original": {
@ -190,11 +248,27 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1755615617,
"narHash": "sha256-HMwfAJBdrr8wXAkbGhtcby1zGFvs+StOp19xNsbqdOg=",
"lastModified": 1722073938,
"narHash": "sha256-OpX0StkL8vpXyWOGUD6G+MA26wAXK6SpT94kLJXo6B4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e36e9f57337d0ff0cf77aceb58af4c805472bfae",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1756542300,
"narHash": "sha256-tlOn88coG5fzdyqz6R93SQL5Gpq+m/DsWpekNFhqPQk=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "20075955deac2583bb12f07151c2df830ef346b4",
"rev": "d7600c775f877cd87b4f5a831c28aa94137377aa",
"type": "github"
},
"original": {
@ -211,11 +285,12 @@
"flake-compat": "flake-compat",
"home-manager": "home-manager",
"impermanence": "impermanence",
"mcp-nixos": "mcp-nixos",
"nix-darwin": "nix-darwin",
"nix-syncthing": "nix-syncthing",
"nix-vscode-extensions": "nix-vscode-extensions",
"nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs",
"nixpkgs": "nixpkgs_2",
"secrets": "secrets",
"sops-nix": "sops-nix",
"steam-fetcher": "steam-fetcher"
@ -291,6 +366,21 @@
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",

View file

@ -76,6 +76,12 @@
url = "github:nix-community/steam-fetcher";
inputs.nixpkgs.follows = "nixpkgs";
};
# MCP NixOS server for Claude Dev
mcp-nixos = {
url = "github:utensils/mcp-nixos";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
@ -157,6 +163,8 @@
disko
# for viewing dconf entries
dconf-editor
# for MCP NixOS server support in development
inputs.mcp-nixos.packages.${system}.default
];
SOPS_AGE_KEY_DIRECTORY = import ./const/sops_age_key_directory.nix;

View file

@ -45,8 +45,13 @@
services.ssh-agent.enable = true;
programs.ssh = {
enable = true;
enableDefaultConfig = false;
matchBlocks = {
"*" = {
compression = true;
addKeysToAgent = "confirm";
};
};
extraConfig = lib.strings.concatLines (
builtins.map (hostKey: "IdentityFile ~/.ssh/${hostKey.path}") config.programs.openssh.hostKeys
);

View file

@ -6,11 +6,13 @@
./makemkv.nix
./obs.nix
./anki.nix
./piper.nix
./qbittorrent.nix
./discord.nix
./obsidian.nix
./prostudiomasters.nix
./idea.nix
./krita.nix
./protonvpn.nix
./calibre.nix
./bruno.nix

View file

@ -0,0 +1,30 @@
{
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.krita = {
enable = lib.mkEnableOption "enable krita";
};
config = lib.mkIf config.programs.krita.enable (lib.mkMerge [
{
home.packages = with pkgs; [
krita
];
}
(
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/kritarc"
"${config.xdg.dataHome}/krita"
];
allowOther = true;
};
}
)
]);
}

View file

@ -0,0 +1,17 @@
{
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.piper = {
enable = lib.mkEnableOption "enable piper";
};
config = lib.mkIf config.programs.piper.enable {
home.packages = with pkgs; [
piper
];
};
}

View file

@ -2,10 +2,29 @@
lib,
pkgs,
config,
inputs,
...
}: let
pkgsRepositories = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version;
pkgsRepository = pkgsRepositories.open-vsx;
mcp-nixos = inputs.mcp-nixos.packages.${pkgs.stdenv.hostPlatform.system}.default;
mcp-eslint = pkgs.writeShellScriptBin "mcp-eslint" ''
${pkgs.nodejs}/bin/npx --yes @modelcontextprotocol/server-eslint "$@"
'';
anyProfileHasMcpNixos = lib.any (
profile:
profile.extraExtensions.claudeDev.enable
&& profile.extraExtensions.claudeDev.mcp.nixos.enable
) (lib.attrValues config.programs.vscode.profiles);
anyProfileHasMcpEslint = lib.any (
profile:
profile.extraExtensions.claudeDev.enable
&& profile.extraExtensions.claudeDev.mcp.eslint.enable
) (lib.attrValues config.programs.vscode.profiles);
in {
options.programs.vscode.profiles = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({config, ...}: {
@ -15,6 +34,15 @@ in {
extension = lib.mkPackageOption pkgsRepository "claude-dev" {
default = ["saoudrizwan" "claude-dev"];
};
mcp = {
nixos = {
enable = lib.mkEnableOption "enable NixOS MCP server for Claude Dev";
};
eslint = {
enable = lib.mkEnableOption "enable ESLint MCP server for Claude Dev";
};
};
};
};
config = lib.mkIf config.extraExtensions.claudeDev.enable {
@ -24,4 +52,38 @@ in {
};
}));
};
config = lib.mkMerge [
(lib.mkIf anyProfileHasMcpNixos {
home.packages = [
mcp-nixos
];
})
(lib.mkIf anyProfileHasMcpEslint {
home.packages = [
mcp-eslint
pkgs.eslint
];
})
(lib.mkIf (anyProfileHasMcpNixos || anyProfileHasMcpEslint) {
home.file."${config.xdg.configHome}/VSCodium/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json" = {
text = builtins.toJSON {
mcpServers =
(lib.optionalAttrs anyProfileHasMcpNixos {
nixos = {
command = "${mcp-nixos}/bin/mcp-nixos";
};
})
// (lib.optionalAttrs anyProfileHasMcpEslint {
eslint = {
command = "${mcp-eslint}/bin/mcp-eslint";
};
});
};
force = true;
};
})
];
}

View file

@ -20,5 +20,6 @@
./vscodeMdx.nix
./claudeDev.nix
./nearley.nix
./vitest.nix
];
}

View file

@ -0,0 +1,27 @@
{
lib,
pkgs,
config,
...
}: let
pkgsRepositories = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version;
pkgsRepository = pkgsRepositories.open-vsx;
in {
options.programs.vscode.profiles = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({config, ...}: {
options = {
extraExtensions.vitest = {
enable = lib.mkEnableOption "should the vitest extension for vscode be enabled";
extension = lib.mkPackageOption pkgsRepository "vitest" {
default = ["vitest" "explorer"];
};
};
};
config = lib.mkIf config.extraExtensions.vitest.enable {
extensions = [
config.extraExtensions.vitest.extension
];
};
}));
};
}

View file

@ -19,6 +19,12 @@ in {
config = lib.mkIf config.services.forgejo.enable (lib.mkMerge [
{
assertions = [
{
assertion = config.services.forgejo.settings.server.BUILTIN_SSH_SERVER_USER == config.users.users.git.name;
message = "Forgejo BUILTIN_SSH_SERVER_USER hardcoded value does not match expected git user name";
}
];
host = {
reverse_proxy.subdomains.${config.services.forgejo.subdomain} = {
target = "http://localhost:${toString forgejoPort}";
@ -52,7 +58,7 @@ in {
START_SSH_SERVER = true;
SSH_LISTEN_PORT = sshPort;
SSH_PORT = 22;
BUILTIN_SSH_SERVER_USER = config.users.users.git.name;
BUILTIN_SSH_SERVER_USER = "git";
ROOT_URL = "https://git.jan-leila.com";
};
service = {

View file

@ -15,7 +15,7 @@ in {
export_directory = lib.mkOption {
type = lib.types.path;
description = "what are exports going to be stored in";
default = "/export";
default = "/exports";
};
directories = lib.mkOption {
type = lib.types.listOf (lib.types.submodule ({config, ...}: {

View file

@ -61,8 +61,6 @@
# loopback
"127.0.0.1"
"::1"
# local network
# "192.168.0.0/24"
# tailscale
"100.64.0.0/10"
"fd7a:115c:a1e0::/48"
@ -84,7 +82,7 @@
);
};
};
networking.firewall.interfaces.${config.services.tailscale.interfaceName} = let
networking.firewall = let
ports = [
111
config.host.network_storage.nfs.port
@ -94,6 +92,12 @@
20048
];
in {
# Allow NFS on Tailscale interface
interfaces.${config.services.tailscale.interfaceName} = {
allowedTCPPorts = ports;
allowedUDPPorts = ports;
};
# Allow NFS on local network (assuming default interface)
allowedTCPPorts = ports;
allowedUDPPorts = ports;
};