formatter and lxc configuration

This commit is contained in:
UGA Innovation Factory
2025-12-10 14:52:34 +00:00
parent d4835360f5
commit 14202a8233
23 changed files with 742 additions and 308 deletions

57
flake.lock generated
View File

@@ -95,6 +95,24 @@
"type": "github" "type": "github"
} }
}, },
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"git-hooks": { "git-hooks": {
"inputs": { "inputs": {
"flake-compat": [ "flake-compat": [
@@ -393,7 +411,8 @@
"lazyvim-nixvim": "lazyvim-nixvim", "lazyvim-nixvim": "lazyvim-nixvim",
"nixos-hardware": "nixos-hardware", "nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs_2", "nixpkgs": "nixpkgs_2",
"nixpkgs-old-kernel": "nixpkgs-old-kernel" "nixpkgs-old-kernel": "nixpkgs-old-kernel",
"vscode-server": "vscode-server"
} }
}, },
"systems": { "systems": {
@@ -411,6 +430,21 @@
"type": "github" "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"
}
},
"treefmt-nix": { "treefmt-nix": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@@ -432,6 +466,27 @@
"repo": "treefmt-nix", "repo": "treefmt-nix",
"type": "github" "type": "github"
} }
},
"vscode-server": {
"inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1753541826,
"narHash": "sha256-foGgZu8+bCNIGeuDqQ84jNbmKZpd+JvnrL2WlyU4tuU=",
"owner": "nix-community",
"repo": "nixos-vscode-server",
"rev": "6d5f074e4811d143d44169ba4af09b20ddb6937d",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixos-vscode-server",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View File

@@ -9,33 +9,51 @@
inputs = { inputs = {
# Core NixOS package repository (Release 25.11) # Core NixOS package repository (Release 25.11)
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
# Older kernel packages for Surface compatibility if needed # Older kernel packages for Surface compatibility if needed
nixpkgs-old-kernel.url = "github:NixOS/nixpkgs/nixos-25.05"; nixpkgs-old-kernel.url = "github:NixOS/nixpkgs/nixos-25.05";
# Home Manager for user environment management # Home Manager for user environment management
home-manager = { home-manager = {
url = "github:nix-community/home-manager/release-25.11"; url = "github:nix-community/home-manager/release-25.11";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
# Disko for declarative disk partitioning # Disko for declarative disk partitioning
disko = { disko = {
url = "github:nix-community/disko"; url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
# Hardware quirks and configurations # Hardware quirks and configurations
nixos-hardware.url = "github:NixOS/nixos-hardware/master"; nixos-hardware.url = "github:NixOS/nixos-hardware/master";
# Neovim configuration # Neovim configuration
lazyvim-nixvim.url = "github:azuwis/lazyvim-nixvim"; lazyvim-nixvim.url = "github:azuwis/lazyvim-nixvim";
};
outputs = inputs@{ self, nixpkgs, nixpkgs-old-kernel, home-manager, disko, lazyvim-nixvim, nixos-hardware,... }: {
# Formatter for 'nix fmt'
formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixfmt-rfc-style;
# Generate NixOS configurations from hosts/default.nix # VS Code server for remote development
nixosConfigurations = import ./hosts { inherit inputs; }; vscode-server = {
url = "github:nix-community/nixos-vscode-server";
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs =
inputs@{
self,
nixpkgs,
nixpkgs-old-kernel,
home-manager,
disko,
lazyvim-nixvim,
nixos-hardware,
vscode-server,
...
}:
{
# Formatter for 'nix fmt'
formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixfmt-rfc-style;
# Generate NixOS configurations from hosts/default.nix
nixosConfigurations = import ./hosts { inherit inputs; };
};
} }

View File

@@ -47,7 +47,10 @@
format = "vfat"; format = "vfat";
mountpoint = "/boot"; mountpoint = "/boot";
mountOptions = [ "umask=0077" ]; mountOptions = [ "umask=0077" ];
extraArgs = [ "-n" "BOOT" ]; extraArgs = [
"-n"
"BOOT"
];
}; };
}; };
@@ -56,7 +59,9 @@
name = "swap"; name = "swap";
label = "swap"; label = "swap";
size = config.host.filesystem.swapSize; size = config.host.filesystem.swapSize;
content = { type = "swap"; }; content = {
type = "swap";
};
}; };
# Root Partition (takes remaining space) # Root Partition (takes remaining space)
@@ -68,7 +73,10 @@
type = "filesystem"; type = "filesystem";
format = "ext4"; format = "ext4";
mountpoint = "/"; mountpoint = "/";
extraArgs = [ "-L" "ROOT" ]; extraArgs = [
"-L"
"ROOT"
];
}; };
}; };
}; };

View File

@@ -1,4 +1,8 @@
{ inputs, hosts ? import ../inventory.nix, ... }: {
inputs,
hosts ? import ../inventory.nix,
...
}:
# ============================================================================ # ============================================================================
# Host Generator # Host Generator
@@ -10,10 +14,10 @@
# 3. External flake integration for system overrides. # 3. External flake integration for system overrides.
let let
nixpkgs = inputs.nixpkgs; nixpkgs = inputs.nixpkgs;
lib = nixpkgs.lib; lib = nixpkgs.lib;
home-manager = inputs.home-manager; home-manager = inputs.home-manager;
disko = inputs.disko; disko = inputs.disko;
# Modules shared by all hosts # Modules shared by all hosts
commonModules = [ commonModules = [
@@ -25,35 +29,44 @@ let
disko.nixosModules.disko disko.nixosModules.disko
{ {
system.stateVersion = "25.11"; system.stateVersion = "25.11";
nix.settings.experimental-features = [ "nix-command" "flakes" ]; nix.settings.experimental-features = [
"nix-command"
"flakes"
];
# Automatic Garbage Collection # Automatic Garbage Collection
nix.gc = { nix.gc = {
automatic = true; automatic = true;
dates = "weekly"; dates = "weekly";
options = "--delete-older-than 30d"; options = "--delete-older-than 30d";
}; };
# Optimize storage # Optimize storage
nix.optimise.automatic = true; nix.optimise.automatic = true;
} }
]; ];
# Helper to create a single NixOS system configuration # Helper to create a single NixOS system configuration
mkHost = { hostName, system ? "x86_64-linux", extraModules ? [ ] }: mkHost =
{
hostName,
system ? "x86_64-linux",
extraModules ? [ ],
}:
let let
# Load users.nix to find external user flakes # Load users.nix to find external user flakes
# We use legacyPackages to evaluate the simple data structure of users.nix # We use legacyPackages to evaluate the simple data structure of users.nix
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
usersData = import ../users.nix { inherit pkgs; }; usersData = import ../users.nix { inherit pkgs; };
accounts = usersData.modules.users.accounts or {}; accounts = usersData.modules.users.accounts or { };
# Extract flakeUrls and convert to modules # Extract flakeUrls and convert to modules
userFlakeModules = lib.mapAttrsToList (name: user: userFlakeModules = lib.mapAttrsToList (
name: user:
if (user ? flakeUrl && user.flakeUrl != "") then if (user ? flakeUrl && user.flakeUrl != "") then
(builtins.getFlake user.flakeUrl).nixosModules.default (builtins.getFlake user.flakeUrl).nixosModules.default
else else
{} { }
) accounts; ) accounts;
in in
lib.nixosSystem { lib.nixosSystem {
@@ -71,56 +84,85 @@ let
}; };
# Function to generate a set of hosts based on inventory count and overrides # Function to generate a set of hosts based on inventory count and overrides
mkHostGroup = { prefix, count, system ? "x86_64-linux", extraModules ? [], deviceOverrides ? {} }: mkHostGroup =
lib.listToAttrs (map (i: { {
name = "${prefix}${toString i}"; prefix,
value = count,
system ? "x86_64-linux",
extraModules ? [ ],
deviceOverrides ? { },
}:
lib.listToAttrs (
lib.concatMap (
i:
let let
devConf = deviceOverrides.${toString i} or {}; defaultName = "${prefix}${toString i}";
devConf = deviceOverrides.${toString i} or { };
hasOverride = builtins.hasAttr (toString i) deviceOverrides; hasOverride = builtins.hasAttr (toString i) deviceOverrides;
hostName =
if hasOverride && (builtins.hasAttr "hostname" devConf) then devConf.hostname else defaultName;
# Extract flakeUrl if it exists # Extract flakeUrl if it exists
externalFlake = if hasOverride && (builtins.hasAttr "flakeUrl" devConf) externalFlake =
then builtins.getFlake devConf.flakeUrl if hasOverride && (builtins.hasAttr "flakeUrl" devConf) then
else null; builtins.getFlake devConf.flakeUrl
else
null;
# Module from external flake # Module from external flake
externalModule = if externalFlake != null externalModule = if externalFlake != null then externalFlake.nixosModules.default else { };
then externalFlake.nixosModules.default
else {};
# Config override module (filesystem, users) # Config override module (filesystem, users)
overrideModule = { ... }: overrideModule =
{ ... }:
let let
# Remove special keys that are not filesystem options # Remove special keys that are not filesystem options
fsConf = builtins.removeAttrs devConf [ "extraUsers" "flakeUrl" ]; fsConf = builtins.removeAttrs devConf [
in lib.mkIf hasOverride { "extraUsers"
"flakeUrl"
"hostname"
];
in
lib.mkIf hasOverride {
host.filesystem = fsConf; host.filesystem = fsConf;
modules.users.enabledUsers = devConf.extraUsers or []; modules.users.enabledUsers = devConf.extraUsers or [ ];
}; };
config = mkHost {
hostName = hostName;
inherit system;
extraModules =
extraModules ++ [ overrideModule ] ++ (lib.optional (externalFlake != null) externalModule);
};
aliasNames = lib.optional (hostName != defaultName) hostName;
names = lib.unique ([ defaultName ] ++ aliasNames);
in in
mkHost { lib.map (name: {
hostName = "${prefix}${toString i}"; inherit name;
inherit system; value = config;
extraModules = extraModules ++ [ overrideModule ] ++ (lib.optional (externalFlake != null) externalModule); }) names
}; ) (lib.range 1 count)
}) (lib.range 1 count)); );
# Generate host groups based on the input hosts configuration # Generate host groups based on the input hosts configuration
hostGroups = lib.mapAttrsToList (type: config: hostGroups = lib.mapAttrsToList (
type: config:
let let
typeFile = ./types + "/${type}.nix"; typeFile = ./types + "/${type}.nix";
modules = if builtins.pathExists typeFile modules =
then import typeFile { inherit inputs; } if builtins.pathExists typeFile then
else throw "Host type '${type}' not found in hosts/types/"; import typeFile { inherit inputs; }
else
throw "Host type '${type}' not found in hosts/types/";
in in
mkHostGroup { mkHostGroup {
prefix = type; prefix = type;
inherit (config) count; inherit (config) count;
extraModules = modules; extraModules = modules;
deviceOverrides = config.devices or {}; deviceOverrides = config.devices or { };
} }
) hosts; ) hosts;
in in
lib.foldl' lib.recursiveUpdate {} hostGroups lib.foldl' lib.recursiveUpdate { } hostGroups

View File

@@ -1,24 +1,42 @@
{ inputs, ... }: [ { inputs, ... }:
({ config, lib, modulesPath, ... }: { [
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; (
{
config,
lib,
modulesPath,
...
}:
{
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" "sdhci_pci" ]; boot.initrd.availableKernelModules = [
boot.initrd.kernelModules = [ ]; "xhci_pci"
boot.kernelModules = [ "kvm-intel" ]; "nvme"
boot.extraModulePackages = [ ]; "usb_storage"
boot.kernelParams = [ "sd_mod"
"quiet" "sdhci_pci"
"splash" ];
"boot.shell_on_fail" boot.initrd.kernelModules = [ ];
"udev.log_priority=3" boot.kernelModules = [ "kvm-intel" ];
"rd.systemd.show_status=auto" boot.extraModulePackages = [ ];
]; boot.kernelParams = [
"quiet"
"splash"
"boot.shell_on_fail"
"udev.log_priority=3"
"rd.systemd.show_status=auto"
];
host.filesystem.swapSize = lib.mkDefault "16G"; host.filesystem.swapSize = lib.mkDefault "16G";
host.filesystem.device = lib.mkDefault "/dev/nvme0n1"; host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}) }
{ modules.sw.enable = true; modules.sw.type = "desktop"; } )
{
modules.sw.enable = true;
modules.sw.type = "desktop";
}
] ]

View File

@@ -1,12 +1,27 @@
{ inputs, ... }: [ { inputs, ... }:
({ config, lib, modulesPath, ... }: { [
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; (
{
config,
lib,
modulesPath,
...
}:
{
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" "sdhci_pci" ]; boot.initrd.availableKernelModules = [
boot.initrd.kernelModules = [ ]; "xhci_pci"
boot.kernelModules = [ "kvm-intel" ]; "thunderbolt"
boot.extraModulePackages = [ ]; "nvme"
boot.kernelParams = [ "usb_storage"
"sd_mod"
"sdhci_pci"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
boot.kernelParams = [
"quiet" "quiet"
"splash" "splash"
"boot.shell_on_fail" "boot.shell_on_fail"
@@ -17,21 +32,25 @@
"i915.enable_fbc=0" "i915.enable_fbc=0"
]; ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
host.filesystem.device = lib.mkDefault "/dev/nvme0n1"; host.filesystem.device = lib.mkDefault "/dev/nvme0n1";
host.filesystem.swapSize = lib.mkDefault "34G"; host.filesystem.swapSize = lib.mkDefault "34G";
# Suspend / logind behavior # Suspend / logind behavior
services.upower.enable = true; services.upower.enable = true;
services.logind.settings = { services.logind.settings = {
Login = { Login = {
HandleLidSwitch = "suspend"; HandleLidSwitch = "suspend";
HandleLidSwitchExternalPower = "suspend"; HandleLidSwitchExternalPower = "suspend";
HandleLidSwitchDocked = "ignore"; HandleLidSwitchDocked = "ignore";
};
}; };
}; }
}) )
{ modules.sw.enable = true; modules.sw.type = "desktop"; } {
modules.sw.enable = true;
modules.sw.type = "desktop";
}
] ]

40
hosts/types/nix-lxc.nix Normal file
View File

@@ -0,0 +1,40 @@
{ inputs, ... }:
[
inputs.vscode-server.nixosModules.default
(
{
config,
lib,
modulesPath,
...
}:
{
nix.settings.trusted-users = [
"root"
"engr-ugaif"
];
nix.settings.experimental-features = [
"nix-command"
"flakes"
];
imports = [
"${modulesPath}/virtualisation/proxmox-lxc.nix"
];
boot.isContainer = true;
boot.loader.systemd-boot.enable = lib.mkForce false;
disko.enableConfig = lib.mkForce false;
console.enable = true;
systemd.services."getty@".unitConfig.ConditionPathExists = [
""
"/dev/%I"
];
systemd.suppressedSystemUnits = [
"dev-mqueue.mount"
"sys-kernel-debug.mount"
"sys-fs-fuse-connections.mount"
];
services.vscode-server.enable = true;
system.stateVersion = "25.11";
}
)
]

View File

@@ -1,40 +1,58 @@
{ inputs, ... }: [ { inputs, ... }:
({ config, lib, pkgs, modulesPath, ... }: [
let (
refSystem = inputs.nixpkgs-old-kernel.lib.nixosSystem { {
system = pkgs.stdenv.hostPlatform.system; config,
modules = [ inputs.nixos-hardware.nixosModules.microsoft-surface-go ]; lib,
}; pkgs,
refKernelPackages = refSystem.config.boot.kernelPackages; modulesPath,
in ...
{ }:
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; let
refSystem = inputs.nixpkgs-old-kernel.lib.nixosSystem {
system = pkgs.stdenv.hostPlatform.system;
modules = [ inputs.nixos-hardware.nixosModules.microsoft-surface-go ];
};
refKernelPackages = refSystem.config.boot.kernelPackages;
in
{
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" "sdhci_pci" ]; boot.initrd.availableKernelModules = [
boot.initrd.kernelModules = [ ]; "xhci_pci"
boot.kernelModules = [ "kvm-intel" ]; "nvme"
boot.extraModulePackages = [ ]; "usb_storage"
boot.kernelParams = [ "sd_mod"
"quiet" "sdhci_pci"
"splash" ];
"boot.shell_on_fail" boot.initrd.kernelModules = [ ];
"udev.log_priority=3" boot.kernelModules = [ "kvm-intel" ];
"rd.systemd.show_status=auto" boot.extraModulePackages = [ ];
"intel_ipu3_imgu" boot.kernelParams = [
"intel_ipu3_isys" "quiet"
"fbcon=map:1" "splash"
"i915.enable_psr=0" # Panel Self Refresh breaks resume on Surface "boot.shell_on_fail"
"i915.enable_dc=0" "udev.log_priority=3"
]; "rd.systemd.show_status=auto"
"intel_ipu3_imgu"
"intel_ipu3_isys"
"fbcon=map:1"
"i915.enable_psr=0" # Panel Self Refresh breaks resume on Surface
"i915.enable_dc=0"
];
boot.kernelPackages = lib.mkForce refKernelPackages; boot.kernelPackages = lib.mkForce refKernelPackages;
host.filesystem.swapSize = lib.mkDefault "8G"; host.filesystem.swapSize = lib.mkDefault "8G";
host.filesystem.device = lib.mkDefault "/dev/mmcblk0"; host.filesystem.device = lib.mkDefault "/dev/mmcblk0";
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}) }
)
inputs.nixos-hardware.nixosModules.microsoft-surface-go inputs.nixos-hardware.nixosModules.microsoft-surface-go
{ modules.sw.enable = true; modules.sw.type = "kiosk"; } {
modules.sw.enable = true;
modules.sw.type = "kiosk";
}
] ]

View File

@@ -1,4 +1,9 @@
{ pkgs, config, lib, ... }: {
pkgs,
config,
lib,
...
}:
# ============================================================================ # ============================================================================
# User Configuration Module # User Configuration Module
@@ -11,19 +16,63 @@ let
# Submodule defining the structure of a user account # Submodule defining the structure of a user account
userSubmodule = lib.types.submodule { userSubmodule = lib.types.submodule {
options = { options = {
isNormalUser = lib.mkOption { type = lib.types.bool; default = true; }; isNormalUser = lib.mkOption {
description = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; }; type = lib.types.bool;
extraGroups = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; }; default = true;
hashedPassword = lib.mkOption { type = lib.types.str; default = "!"; }; };
extraPackages = lib.mkOption { type = lib.types.listOf lib.types.package; default = []; }; description = lib.mkOption {
excludePackages = lib.mkOption { type = lib.types.listOf lib.types.package; default = []; }; type = lib.types.nullOr lib.types.str;
homePackages = lib.mkOption { type = lib.types.listOf lib.types.package; default = []; }; default = null;
extraImports = lib.mkOption { type = lib.types.listOf lib.types.path; default = []; }; };
flakeUrl = lib.mkOption { type = lib.types.str; default = ""; description = "URL of a flake to import Home Manager configuration from (e.g. github:user/dotfiles)."; }; extraGroups = lib.mkOption {
opensshKeys = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; description = "List of SSH public keys for the user."; }; type = lib.types.listOf lib.types.str;
shell = lib.mkOption { type = lib.types.nullOr lib.types.package; default = null; description = "The shell for this user."; }; default = [ ];
useZshTheme = lib.mkOption { type = lib.types.bool; default = true; description = "Whether to apply the system Zsh theme."; }; };
useNvimPlugins = lib.mkOption { type = lib.types.bool; default = true; description = "Whether to apply the system Neovim configuration."; }; hashedPassword = lib.mkOption {
type = lib.types.str;
default = "!";
};
extraPackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
excludePackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
homePackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
extraImports = lib.mkOption {
type = lib.types.listOf lib.types.path;
default = [ ];
};
flakeUrl = lib.mkOption {
type = lib.types.str;
default = "";
description = "URL of a flake to import Home Manager configuration from (e.g. github:user/dotfiles).";
};
opensshKeys = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "List of SSH public keys for the user.";
};
shell = lib.mkOption {
type = lib.types.nullOr lib.types.package;
default = null;
description = "The shell for this user.";
};
useZshTheme = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to apply the system Zsh theme.";
};
useNvimPlugins = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to apply the system Neovim configuration.";
};
}; };
}; };
in in
@@ -36,71 +85,85 @@ in
}; };
accounts = lib.mkOption { accounts = lib.mkOption {
type = lib.types.attrsOf userSubmodule; type = lib.types.attrsOf userSubmodule;
default = {}; default = { };
description = "User accounts configuration."; description = "User accounts configuration.";
}; };
enabledUsers = lib.mkOption { enabledUsers = lib.mkOption {
type = lib.types.listOf lib.types.str; type = lib.types.listOf lib.types.str;
default = []; default = [ ];
description = "List of users to enable on this system."; description = "List of users to enable on this system.";
}; };
}; };
config = { config = {
# Default enabled users (always present) # Default enabled users (always present)
modules.users.enabledUsers = [ "root" "engr-ugaif" ]; modules.users.enabledUsers = [
"root"
"engr-ugaif"
];
# Generate NixOS users # Generate NixOS users
users.users = users.users =
let let
enabledAccounts = lib.filterAttrs (name: _: lib.elem name config.modules.users.enabledUsers) config.modules.users.accounts; enabledAccounts = lib.filterAttrs (
name: _: lib.elem name config.modules.users.enabledUsers
) config.modules.users.accounts;
in in
lib.mapAttrs (name: user: lib.mapAttrs (
let name: user:
isPlasma6 = config.services.desktopManager.plasma6.enable; let
defaultPackages = lib.optionals (isPlasma6 && name != "root") [ pkgs.kdePackages.kate ]; isPlasma6 = config.services.desktopManager.plasma6.enable;
finalPackages = lib.subtractLists user.excludePackages (defaultPackages ++ user.extraPackages); defaultPackages = lib.optionals (isPlasma6 && name != "root") [ pkgs.kdePackages.kate ];
in finalPackages = lib.subtractLists user.excludePackages (defaultPackages ++ user.extraPackages);
{ in
inherit (user) isNormalUser extraGroups hashedPassword; {
description = if user.description != null then user.description else lib.mkDefault ""; inherit (user) isNormalUser extraGroups hashedPassword;
openssh.authorizedKeys.keys = user.opensshKeys; description = if user.description != null then user.description else lib.mkDefault "";
packages = finalPackages; openssh.authorizedKeys.keys = user.opensshKeys;
shell = if user.shell != null then user.shell else config.modules.users.shell; packages = finalPackages;
} shell = if user.shell != null then user.shell else config.modules.users.shell;
) enabledAccounts; }
) enabledAccounts;
# Home Manager configs per user # Home Manager configs per user
home-manager = { home-manager = {
useGlobalPkgs = true; useGlobalPkgs = true;
useUserPackages = true; useUserPackages = true;
extraSpecialArgs = { osConfig = config; }; extraSpecialArgs = {
osConfig = config;
};
users = users =
let let
enabledAccounts = lib.filterAttrs (name: _: lib.elem name config.modules.users.enabledUsers) config.modules.users.accounts; enabledAccounts = lib.filterAttrs (
name: _: lib.elem name config.modules.users.enabledUsers
) config.modules.users.accounts;
in in
lib.mapAttrs (name: user: { ... }: lib.mapAttrs (
name: user:
{ ... }:
let let
isExternal = user.flakeUrl != ""; isExternal = user.flakeUrl != "";
# Common imports based on flags # Common imports based on flags
commonImports = commonImports =
lib.optional user.useZshTheme ../sw/theme.nix lib.optional user.useZshTheme ../sw/theme.nix ++ lib.optional user.useNvimPlugins ../sw/nvim.nix;
++ lib.optional user.useNvimPlugins ../sw/nvim.nix;
in in
if isExternal then { if isExternal then
# External users: Only apply requested system modules. {
# The external flake is responsible for home.username, home.packages, etc. # External users: Only apply requested system modules.
imports = commonImports; # The external flake is responsible for home.username, home.packages, etc.
} else { imports = commonImports;
# Local users: Apply full configuration. }
imports = user.extraImports ++ commonImports; else
home.username = name; {
home.homeDirectory = if name == "root" then "/root" else "/home/${name}"; # Local users: Apply full configuration.
home.stateVersion = "25.11"; imports = user.extraImports ++ commonImports;
home.packages = user.homePackages; home.username = name;
} home.homeDirectory = if name == "root" then "/root" else "/home/${name}";
home.stateVersion = "25.11";
home.packages = user.homePackages;
}
) enabledAccounts; ) enabledAccounts;
}; };
}; };

View File

@@ -24,11 +24,15 @@
devices = { devices = {
# Override example: # Override example:
# "2" = { swapSize = "64G"; }; # "2" = { swapSize = "64G"; };
# Enable specific users for this device index # Enable specific users for this device index
"1" = { extraUsers = [ "hdh20267" ]; }; "1" = {
"2" = { extraUsers = [ "hdh20267" ]; }; extraUsers = [ "hdh20267" ];
};
"2" = {
extraUsers = [ "hdh20267" ];
};
# Example of using an external flake for system configuration: # Example of using an external flake for system configuration:
# "2" = { flakeUrl = "github:user/system-flake"; }; # "2" = { flakeUrl = "github:user/system-flake"; };
}; };
@@ -41,4 +45,14 @@
# Surface Tablet Configuration (Kiosk Mode) # Surface Tablet Configuration (Kiosk Mode)
# Base specs: eMMC drive, 8G Swap # Base specs: eMMC drive, 8G Swap
nix-surface.count = 3; nix-surface.count = 3;
# LXC Container Configuration
nix-lxc = {
count = 1;
devices = {
"1" = {
hostname = "nix-builder";
};
};
};
} }

View File

@@ -1,4 +1,10 @@
{ config, lib, pkgs, inputs, ... }: {
config,
lib,
pkgs,
inputs,
...
}:
# ============================================================================ # ============================================================================
# Software Module Entry Point # Software Module Entry Point
@@ -22,20 +28,23 @@ in
enable = mkEnableOption "Standard Workstation Configuration"; enable = mkEnableOption "Standard Workstation Configuration";
type = mkOption { type = mkOption {
type = types.enum [ "desktop" "kiosk" ]; type = types.enum [
"desktop"
"kiosk"
];
default = "desktop"; default = "desktop";
description = "Type of system configuration: 'desktop' for normal OS, 'kiosk' for tablet/kiosk mode."; description = "Type of system configuration: 'desktop' for normal OS, 'kiosk' for tablet/kiosk mode.";
}; };
extraPackages = mkOption { extraPackages = mkOption {
type = types.listOf types.package; type = types.listOf types.package;
default = []; default = [ ];
description = "Extra packages to install."; description = "Extra packages to install.";
}; };
excludePackages = mkOption { excludePackages = mkOption {
type = types.listOf types.package; type = types.listOf types.package;
default = []; default = [ ];
description = "Packages to exclude from the default list."; description = "Packages to exclude from the default list.";
}; };
@@ -49,37 +58,57 @@ in
config = mkIf cfg.enable (mkMerge [ config = mkIf cfg.enable (mkMerge [
{ {
nixpkgs.config.allowUnfree = true; nixpkgs.config.allowUnfree = true;
programs.zsh.enable = true; programs.zsh.enable = true;
programs.nix-ld.enable = true; programs.nix-ld.enable = true;
environment.systemPackages = with pkgs; subtractLists cfg.excludePackages [ environment.systemPackages =
htop with pkgs;
binutils subtractLists cfg.excludePackages [
zsh htop
git binutils
oh-my-posh zsh
inputs.lazyvim-nixvim.packages.${stdenv.hostPlatform.system}.nvim git
# Custom update script oh-my-posh
(writeShellScriptBin "update-system" '' inputs.lazyvim-nixvim.packages.${stdenv.hostPlatform.system}.nvim
HOSTNAME=$(hostname) # Custom update script
FLAKE_URI="github:UGA-Innovation-Factory/nixos-systems" (writeShellScriptBin "update-system" ''
HOSTNAME=$(hostname)
# Pass arguments like --impure to nixos-rebuild FLAKE_URI="github:UGA-Innovation-Factory/nixos-systems"
EXTRA_ARGS="$@"
if [[ "$HOSTNAME" == nix-surface* ]]; then # Pass arguments like --impure to nixos-rebuild
echo "Detected Surface tablet. Using remote build host." EXTRA_ARGS="$@"
sudo nixos-rebuild switch --flake "$FLAKE_URI" --build-host engr-ugaif@192.168.11.133 --refresh $EXTRA_ARGS
else if [[ "$HOSTNAME" == nix-surface* ]]; then
echo "Updating local system..." echo "Detected Surface tablet. Using remote build host."
sudo nixos-rebuild switch --flake "$FLAKE_URI" --refresh $EXTRA_ARGS sudo nixos-rebuild switch --flake "$FLAKE_URI" --build-host engr-ugaif@192.168.11.133 --refresh $EXTRA_ARGS
fi else
'') echo "Updating local system..."
]; sudo nixos-rebuild switch --flake "$FLAKE_URI" --refresh $EXTRA_ARGS
fi
'')
];
} }
# Import Desktop or Kiosk modules based on type # Import Desktop or Kiosk modules based on type
(mkIf (cfg.type == "desktop") (import ./desktop { inherit config lib pkgs inputs; })) (mkIf (cfg.type == "desktop") (
(mkIf (cfg.type == "kiosk") (import ./kiosk { inherit config lib pkgs inputs; })) import ./desktop {
inherit
config
lib
pkgs
inputs
;
}
))
(mkIf (cfg.type == "kiosk") (
import ./kiosk {
inherit
config
lib
pkgs
inputs
;
}
))
]); ]);
} }

View File

@@ -1,5 +1,25 @@
{ config, lib, pkgs, inputs, ... }: {
config,
lib,
pkgs,
inputs,
...
}:
lib.mkMerge [ lib.mkMerge [
(import ./programs.nix { inherit config lib pkgs inputs; }) (import ./programs.nix {
(import ./services.nix { inherit config lib pkgs inputs; }) inherit
config
lib
pkgs
inputs
;
})
(import ./services.nix {
inherit
config
lib
pkgs
inputs
;
})
] ]

View File

@@ -1,4 +1,10 @@
{ config, lib, pkgs, inputs, ... }: {
config,
lib,
pkgs,
inputs,
...
}:
with lib; with lib;
@@ -15,7 +21,8 @@ let
teams-for-linux teams-for-linux
wpsoffice wpsoffice
]; ];
in { in
{
environment.systemPackages = subtractLists cfg.excludePackages (basePackages ++ cfg.extraPackages); environment.systemPackages = subtractLists cfg.excludePackages (basePackages ++ cfg.extraPackages);
programs.mtr.enable = true; programs.mtr.enable = true;

View File

@@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
{ {
modules.sw.python.enable = lib.mkDefault true; modules.sw.python.enable = lib.mkDefault true;

View File

@@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
# ============================================================================ # ============================================================================
# Ghostty Terminfo Module # Ghostty Terminfo Module
@@ -8,7 +13,7 @@
# adds it to the system packages. # adds it to the system packages.
let let
ghostty-terminfo = pkgs.runCommand "ghostty-terminfo" {} '' ghostty-terminfo = pkgs.runCommand "ghostty-terminfo" { } ''
mkdir -p $out/share/terminfo mkdir -p $out/share/terminfo
cat > ghostty.info <<'EOF' cat > ghostty.info <<'EOF'
xterm-ghostty|ghostty|Ghostty, xterm-ghostty|ghostty|Ghostty,

View File

@@ -1,6 +1,33 @@
{ config, lib, pkgs, inputs, ... }: {
config,
lib,
pkgs,
inputs,
...
}:
lib.mkMerge [ lib.mkMerge [
(import ./programs.nix { inherit config lib pkgs inputs; }) (import ./programs.nix {
(import ./services.nix { inherit config lib pkgs inputs; }) inherit
(import ./gsettings.nix { inherit config lib pkgs inputs; }) config
lib
pkgs
inputs
;
})
(import ./services.nix {
inherit
config
lib
pkgs
inputs
;
})
(import ./gsettings.nix {
inherit
config
lib
pkgs
inputs
;
})
] ]

View File

@@ -1,50 +1,58 @@
{ config, lib, inputs, ... }: {
config,
lib,
inputs,
...
}:
let let
cfg = config.modules.sw; cfg = config.modules.sw;
in { in
{
programs.dconf = { programs.dconf = {
enable = true; enable = true;
profiles.user = { profiles.user = {
databases = [{ databases = [
settings = { {
"org/gnome/desktop/interface" = { settings = {
color-scheme = "prefer-dark"; "org/gnome/desktop/interface" = {
clock-format = "12h"; color-scheme = "prefer-dark";
clock-show-weekday = true; clock-format = "12h";
show-battery-percentage = true; clock-show-weekday = true;
show-battery-percentage = true;
};
"org/gnome/desktop/media-handling" = {
automount = false;
automount-open = false;
autorun-never = true;
};
"org/gnome/settings-daemon/plugins/power" = {
sleep-inactive-ac-type = "nothing";
};
"org/gnome/desktop/lockdown" = {
disable-lock-screen = true;
};
"org/gnome/desktop/screensaver" = {
lock-enabled = false;
};
"org/gnome/desktop/session" = {
idle-delay = inputs.nixpkgs.lib.gvariant.mkUint32 0;
};
"org/gnome/desktop/input-sources" = {
sources = "[('ibus', 'xkb:us::eng')]";
};
"org/gnome/desktop/mru-sources" = {
sources = "[('ibus', 'xkb:us::eng')]";
};
"sm/puri/phosh" = {
lock-enabled = false;
};
"org/gnome/desktop/a11y/applications" = {
screen-keyboard-enabled = true;
};
}; };
"org/gnome/desktop/media-handling" = { }
automount = false; ];
automount-open = false;
autorun-never = true;
};
"org/gnome/settings-daemon/plugins/power" = {
sleep-inactive-ac-type = "nothing";
};
"org/gnome/desktop/lockdown" = {
disable-lock-screen = true;
};
"org/gnome/desktop/screensaver" = {
lock-enabled = false;
};
"org/gnome/desktop/session" = {
idle-delay = inputs.nixpkgs.lib.gvariant.mkUint32 0;
};
"org/gnome/desktop/input-sources" = {
sources = "[('ibus', 'xkb:us::eng')]";
};
"org/gnome/desktop/mru-sources" = {
sources = "[('ibus', 'xkb:us::eng')]";
};
"sm/puri/phosh" = {
lock-enabled = false;
};
"org/gnome/desktop/a11y/applications" = {
screen-keyboard-enabled = true;
};
};
}];
}; };
}; };
} }

View File

@@ -1,4 +1,10 @@
{ config, lib, pkgs, inputs, ... }: {
config,
lib,
pkgs,
inputs,
...
}:
with lib; with lib;
@@ -13,7 +19,8 @@ let
phoc phoc
gsettings-desktop-schemas gsettings-desktop-schemas
]; ];
in { in
{
environment.systemPackages = subtractLists cfg.excludePackages (basePackages ++ cfg.extraPackages); environment.systemPackages = subtractLists cfg.excludePackages (basePackages ++ cfg.extraPackages);
programs.chromium = { programs.chromium = {

View File

@@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
{ {
services.xserver = { services.xserver = {
@@ -28,7 +33,7 @@
enable = true; enable = true;
ibus.engines = [ pkgs.ibus-engines.m17n ]; ibus.engines = [ pkgs.ibus-engines.m17n ];
}; };
services.gnome.gnome-keyring.enable = lib.mkForce false; services.gnome.gnome-keyring.enable = lib.mkForce false;
environment.sessionVariables = { environment.sessionVariables = {
@@ -36,9 +41,10 @@
GDK_DPI_SCALE = "0.5"; GDK_DPI_SCALE = "0.5";
# Make GLib / gsettings actually see schemas # Make GLib / gsettings actually see schemas
XDG_DATA_DIRS = [ "/run/current-system/sw/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}" ]; XDG_DATA_DIRS = [
GSETTINGS_SCHEMA_DIR = "/run/current-system/sw/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}"
"/run/current-system/sw/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}/glib-2.0/schemas"; ];
GSETTINGS_SCHEMA_DIR = "/run/current-system/sw/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}/glib-2.0/schemas";
}; };
environment.etc."machine-info".text = '' environment.etc."machine-info".text = ''
@@ -46,12 +52,12 @@
''; '';
services.logind.settings.Login = { services.logind.settings.Login = {
HandlePowerKey="ignore"; HandlePowerKey = "ignore";
HandleSuspendKey="ignore"; HandleSuspendKey = "ignore";
HandleHibernateKey="ignore"; HandleHibernateKey = "ignore";
HandleLidSwitch="ignore"; HandleLidSwitch = "ignore";
HandleLidSwitchExternalPower="ignore"; HandleLidSwitchExternalPower = "ignore";
IdleAction="ignore"; IdleAction = "ignore";
}; };
# Enable networking # Enable networking
@@ -90,7 +96,7 @@
systemd.user.services.squeekboard = { systemd.user.services.squeekboard = {
description = "Squeekboard on-screen keyboard"; description = "Squeekboard on-screen keyboard";
wantedBy = [ "graphical-session.target" ]; wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session.target" ]; partOf = [ "graphical-session.target" ];
serviceConfig = { serviceConfig = {
ExecStart = "${pkgs.squeekboard}/bin/squeekboard"; ExecStart = "${pkgs.squeekboard}/bin/squeekboard";
@@ -101,7 +107,7 @@
systemd.user.services."force-osk" = { systemd.user.services."force-osk" = {
description = "Force the OSK to Enable"; description = "Force the OSK to Enable";
wantedBy = [ "chromium-kiosk.service" ]; wantedBy = [ "chromium-kiosk.service" ];
partOf = [ "chromium-kiosk.service" ]; partOf = [ "chromium-kiosk.service" ];
serviceConfig = { serviceConfig = {
ExecStartPre = '' ExecStartPre = ''
@@ -117,7 +123,7 @@
systemd.user.services."force-input-sources" = { systemd.user.services."force-input-sources" = {
description = "Force the Gsettings Input Sources"; description = "Force the Gsettings Input Sources";
wantedBy = [ "chromium-kiosk.service" ]; wantedBy = [ "chromium-kiosk.service" ];
partOf = [ "chromium-kiosk.service" ]; partOf = [ "chromium-kiosk.service" ];
serviceConfig = { serviceConfig = {
ExecStartPre = '' ExecStartPre = ''
@@ -137,7 +143,7 @@
systemd.user.services."chromium-kiosk" = { systemd.user.services."chromium-kiosk" = {
description = "Chromium kiosk"; description = "Chromium kiosk";
wantedBy = [ "graphical-session.target" ]; wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session.target" ]; partOf = [ "graphical-session.target" ];
serviceConfig = { serviceConfig = {
ExecStart = '' ExecStart = ''

View File

@@ -5,16 +5,19 @@
# ============================================================================ # ============================================================================
# This module configures Neovim, specifically setting up TreeSitter parsers # This module configures Neovim, specifically setting up TreeSitter parsers
# to ensure syntax highlighting works correctly. # to ensure syntax highlighting works correctly.
# https://github.com/nvim-treesitter/nvim-treesitter#i-get-query-error-invalid-node-type-at-position # https://github.com/nvim-treesitter/nvim-treesitter#i-get-query-error-invalid-node-type-at-position
xdg.configFile."nvim/parser".source = xdg.configFile."nvim/parser".source =
let let
parsers = pkgs.symlinkJoin { parsers = pkgs.symlinkJoin {
name = "treesitter-parsers"; name = "treesitter-parsers";
paths = (pkgs.vimPlugins.nvim-treesitter.withPlugins (plugins: with plugins; [ paths =
c (pkgs.vimPlugins.nvim-treesitter.withPlugins (
lua plugins: with plugins; [
])).dependencies; c
lua
]
)).dependencies;
}; };
in in
"${parsers}/parser"; "${parsers}/parser";

View File

@@ -1,4 +1,9 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
# ============================================================================ # ============================================================================
# Python Environment # Python Environment
@@ -11,7 +16,8 @@ with lib;
let let
cfg = config.modules.sw.python; cfg = config.modules.sw.python;
in { in
{
options.modules.sw.python = { options.modules.sw.python = {
enable = mkEnableOption "Python development tools (pixi, uv)"; enable = mkEnableOption "Python development tools (pixi, uv)";
}; };

View File

@@ -1,4 +1,10 @@
{ pkgs, config, osConfig, lib, ... }: {
pkgs,
config,
osConfig,
lib,
...
}:
# ============================================================================ # ============================================================================
# Shell Theme Configuration # Shell Theme Configuration
@@ -14,7 +20,7 @@ let
}; };
# Make a root variant with red username (wraps {{ .UserName }} with ANSI red) # Make a root variant with red username (wraps {{ .UserName }} with ANSI red)
jyumppRootTheme = pkgs.runCommand "jyumpp-root.omp.json" {} '' jyumppRootTheme = pkgs.runCommand "jyumpp-root.omp.json" { } ''
sed -E 's|\{\{[[:space:]]*\.UserName[[:space:]]*\}\}|<#FF3B30>{{ .UserName }}</>|g' \ sed -E 's|\{\{[[:space:]]*\.UserName[[:space:]]*\}\}|<#FF3B30>{{ .UserName }}</>|g' \
${jyumppTheme} > $out ${jyumppTheme} > $out
''; '';

View File

@@ -16,13 +16,23 @@
}; };
engr-ugaif = { engr-ugaif = {
description = "UGA Innovation Factory"; description = "UGA Innovation Factory";
extraGroups = [ "networkmanager" "wheel" "video" "input" ]; extraGroups = [
"networkmanager"
"wheel"
"video"
"input"
];
hashedPassword = "$6$El6e2NhPrhVFjbFU$imlGZqUiizWw5fMP/ib0CeboOcFhYjIVb8oR1V1dP2NjDeri3jMoUm4ZABOB2uAF8UEDjAGHhFuZxhtbHg647/"; hashedPassword = "$6$El6e2NhPrhVFjbFU$imlGZqUiizWw5fMP/ib0CeboOcFhYjIVb8oR1V1dP2NjDeri3jMoUm4ZABOB2uAF8UEDjAGHhFuZxhtbHg647/";
opensshKeys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBC7xzHxY2BfFUybMvG4wHSF9oEAGzRiLTFEndLvWV/X hdh20267@engr733847d.engr.uga.edu" ]; opensshKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBC7xzHxY2BfFUybMvG4wHSF9oEAGzRiLTFEndLvWV/X hdh20267@engr733847d.engr.uga.edu"
];
}; };
hdh20267 = { hdh20267 = {
description = "Hunter Halloran"; description = "Hunter Halloran";
extraGroups = [ "networkmanager" "wheel" ]; extraGroups = [
"networkmanager"
"wheel"
];
homePackages = [ pkgs.ghostty ]; homePackages = [ pkgs.ghostty ];
shell = pkgs.zsh; shell = pkgs.zsh;
# Example of using an external flake for configuration: # Example of using an external flake for configuration: