From 11edaada843f7a3da5ee8543637d8b234ca0476d Mon Sep 17 00:00:00 2001 From: UGA Innovation Factory Date: Tue, 16 Dec 2025 16:09:08 -0500 Subject: [PATCH] feat: Add templates for external configs --- EXTERNAL_MODULES.md | 109 +++++++++++++ README.md | 14 +- USER_CONFIGURATION.md | 288 +++++++++++++++++++++++++++++++++++ flake.nix | 3 + hosts/default.nix | 77 ++++++++-- hosts/user-config.nix | 43 ++++-- inventory.nix | 46 +++++- sw/updater.nix | 5 + templates/default.nix | 40 +++++ templates/system/.gitignore | 3 + templates/system/README.md | 99 ++++++++++++ templates/system/default.nix | 56 +++++++ templates/user/.gitignore | 3 + templates/user/README.md | 183 ++++++++++++++++++++++ templates/user/home.nix | 91 +++++++++++ templates/user/nixos.nix | 47 ++++++ users.nix | 18 ++- 17 files changed, 1102 insertions(+), 23 deletions(-) create mode 100644 EXTERNAL_MODULES.md create mode 100644 USER_CONFIGURATION.md create mode 100644 templates/default.nix create mode 100644 templates/system/.gitignore create mode 100644 templates/system/README.md create mode 100644 templates/system/default.nix create mode 100644 templates/user/.gitignore create mode 100644 templates/user/README.md create mode 100644 templates/user/home.nix create mode 100644 templates/user/nixos.nix diff --git a/EXTERNAL_MODULES.md b/EXTERNAL_MODULES.md new file mode 100644 index 0000000..e336f80 --- /dev/null +++ b/EXTERNAL_MODULES.md @@ -0,0 +1,109 @@ +# External Module Support Implementation + +## Summary + +Modified `nixos-systems` to support external system configurations via Nix modules instead of flakes. Device configurations can now point to URLs using `builtins.fetchGit`, `builtins.fetchTarball`, or local paths. + +## Changes Made + +### 1. `inventory.nix` +- Added documentation for external module syntax +- Added comprehensive examples showing different fetch methods +- Demonstrated usage: `devices."hostname" = builtins.fetchGit { url = "..."; rev = "..."; }` + +### 2. `hosts/default.nix` +- Modified `mkHost` function to accept `externalModulePath` parameter +- Added logic to import and integrate external modules into the module list +- Updated device processing to detect path/derivation types (from fetchGit/fetchTarball) +- External modules are imported with `{ inputs; }` parameter, receiving same flake inputs +- External modules are merged alongside other configuration modules + +### 3. `system-module-template/` +- Created `default.nix` template showing proper module structure +- Created `README.md` with usage instructions and examples +- Documented how external modules integrate with nixos-systems + +## How It Works + +### In inventory.nix: +```nix +{ + "my-type" = { + devices = { + # Option 1: Traditional config attrset + "local-host" = { + extraUsers = [ "user1" ]; + # ... normal NixOS config + }; + + # Option 2: External module from Git + "remote-host" = builtins.fetchGit { + url = "https://github.com/org/config"; + rev = "abc123..."; + }; + }; + }; +} +``` + +### Detection Logic: +The system detects if a device value is: +1. A path (`builtins.isPath`) +2. A string starting with `/` (absolute path) +3. A derivation (`lib.isDerivation`) + +If any of these are true, it treats it as an external module path. + +### Module Import: +External modules are imported as: +```nix +import externalModulePath { inherit inputs; } +``` + +They receive the same flake inputs and can use all available modules and packages. + +### Integration Order: +1. User flake modules (from users.nix) +2. Host type module (from hosts/types/) +3. Config override module +4. Hostname assignment +5. External flake module (if flakeUrl specified in config) +6. External path module (if fetchGit/fetchurl/path detected) + +## Benefits + +- **Separation**: Keep system configs in separate repos +- **Reusability**: Share configs across multiple deployments +- **Versioning**: Pin to specific commits for reproducibility +- **Flexibility**: Mix external modules with local overrides +- **Compatibility**: Works with all existing build methods (ISO, LXC, Proxmox) + +## Testing + +All existing configurations continue to work: +```bash +nix flake check # Passes ✓ +nix eval .#nixosConfigurations.nix-desktop1.config.networking.hostName # Works ✓ +``` + +## Example External Module Repository Structure + +``` +my-server-config/ +├── default.nix # Main module (required) +├── README.md # Documentation +└── custom-service.nix # Additional modules (optional) +``` + +The `default.nix` must export a NixOS module: +```nix +{ inputs, ... }: + +{ config, lib, pkgs, ... }: + +{ + config = { + # Your configuration here + }; +} +``` diff --git a/README.md b/README.md index e68cf4c..a4d7330 100644 --- a/README.md +++ b/README.md @@ -305,7 +305,19 @@ The external flake must provide a `nixosModules.default` output. See [System Fla ## External Flake Templates -If you're creating a flake to use with `flakeUrl`, use these templates as starting points. +If you're creating a flake to use with `flakeUrl`, you can use the provided templates as starting points. + +### Quick Start with Templates + +Initialize a new configuration from templates: + +```bash +# User configuration template (for users.nix) +nix flake init -t github:UGA-Innovation-Factory/nixos-systems#user + +# System configuration template (for inventory.nix) +nix flake init -t github:UGA-Innovation-Factory/nixos-systems#system +``` **Important:** Do not specify `inputs` in your flake. This ensures your flake uses the exact same `nixpkgs` version as the main system, preventing version drift and saving disk space. diff --git a/USER_CONFIGURATION.md b/USER_CONFIGURATION.md new file mode 100644 index 0000000..f9ef083 --- /dev/null +++ b/USER_CONFIGURATION.md @@ -0,0 +1,288 @@ +# External User Configuration + +This document explains how to use external modules for user configuration in nixos-systems. + +## Overview + +Users can now maintain their home-manager configurations in separate Git repositories and reference them from `users.nix` using `builtins.fetchGit`, similar to how external system configurations work. + +## Changes from Previous System + +### Before (Flakes) +```nix +hdh20267 = { + description = "Hunter Halloran"; + flakeUrl = "github:hdh20267/dotfiles"; +}; +``` + +### After (Modules with fetchGit) +```nix +hdh20267 = { + description = "Hunter Halloran"; + home = builtins.fetchGit { + url = "https://github.com/hdh20267/dotfiles"; + rev = "abc123..."; + }; +}; +``` + +## Configuration Methods + +### 1. External Repository (fetchGit) + +```nix +myuser = { + description = "My Name"; + extraGroups = [ "wheel" "networkmanager" ]; + home = builtins.fetchGit { + url = "https://github.com/username/dotfiles"; + rev = "commit-hash"; # For reproducibility + ref = "main"; # Optional branch + }; +}; +``` + +### 2. Local Path (for testing) + +```nix +myuser = { + description = "My Name"; + home = /home/username/dev/dotfiles; +}; +``` + +### 3. Inline Configuration + +```nix +myuser = { + description = "My Name"; + home = { + home.packages = with pkgs; [ vim git ]; + programs.git = { + enable = true; + userName = "My Name"; + }; + }; +}; +``` + +### 4. No External Config (legacy) + +```nix +myuser = { + description = "My Name"; + homePackages = [ pkgs.vim ]; + # home = null; # Default +}; +``` + +## External Repository Structure + +When using `fetchGit` or a path, the repository must contain: + +### Required: home.nix + +```nix +{ inputs, ... }: + +{ config, lib, pkgs, osConfig, ... }: + +{ + # Home-manager configuration + home.packages = with pkgs; [ ... ]; + programs.git = { ... }; +} +``` + +### Optional: nixos.nix + +```nix +{ inputs, ... }: + +{ config, lib, pkgs, ... }: + +{ + # System-level configuration (if needed) + users.users.myuser.extraGroups = [ "docker" ]; +} +``` + +## Integration with System + +External user modules: + +1. **Receive inputs**: Same flake inputs as nixos-systems (nixpkgs, home-manager, etc.) +2. **Access osConfig**: Can read system configuration via `osConfig` parameter +3. **Merged with system settings**: Combined with inventory.nix user settings +4. **System themes applied**: Zsh/nvim themes from system if enabled + +### Module Loading Order + +For home-manager configuration: +1. External module (`home.nix`) +2. System theme module (if `useZshTheme = true`) +3. System nvim config (if `useNvimPlugins = true`) + +For NixOS configuration: +1. User's NixOS module (`nixos.nix`, if exists) +2. All other system modules + +## Available Parameters + +In `home.nix`, you receive: +- `inputs` - Flake inputs (nixpkgs, home-manager, etc.) +- `config` - Home-manager configuration +- `lib` - Nixpkgs library functions +- `pkgs` - Package set +- `osConfig` - OS-level configuration (readonly) + +In `nixos.nix`, you receive: +- `inputs` - Flake inputs +- `config` - NixOS configuration +- `lib` - Nixpkgs library functions +- `pkgs` - Package set + +## User Options in users.nix + +When defining a user with external config: + +```nix +username = { + # Required + description = "Full Name"; + + # External configuration + home = builtins.fetchGit { ... }; + + # System settings (still configured here) + extraGroups = [ "wheel" ]; + hashedPassword = "$6$..."; + opensshKeys = [ "ssh-ed25519 ..." ]; + shell = pkgs.zsh; + + # Control system integration + useZshTheme = true; # Apply system zsh theme + useNvimPlugins = true; # Apply system nvim config + + # Legacy options (ignored if home is set) + homePackages = [ ]; # Use home.packages in home.nix instead + extraImports = [ ]; # Use imports in home.nix instead +}; +``` + +## Examples + +### Minimal Dotfiles Repository + +``` +my-dotfiles/ +├── home.nix +└── README.md +``` + +**home.nix:** +```nix +{ inputs, ... }: +{ config, lib, pkgs, ... }: +{ + home.packages = with pkgs; [ vim git htop ]; + + programs.git = { + enable = true; + userName = "My Name"; + userEmail = "me@example.com"; + }; +} +``` + +### With Dotfiles + +``` +my-dotfiles/ +├── home.nix +├── nixos.nix +├── dotfiles/ +│ ├── bashrc +│ └── vimrc +└── README.md +``` + +**home.nix:** +```nix +{ inputs, ... }: +{ config, lib, pkgs, ... }: +{ + home.file.".bashrc".source = ./dotfiles/bashrc; + home.file.".vimrc".source = ./dotfiles/vimrc; + + programs.git = { + enable = true; + userName = "My Name"; + userEmail = "me@example.com"; + }; +} +``` + +### With System Configuration + +**nixos.nix:** +```nix +{ inputs, ... }: +{ config, lib, pkgs, ... }: +{ + # Add user to docker group + users.users.myusername.extraGroups = [ "docker" ]; + + # Install system-level packages + environment.systemPackages = [ pkgs.docker ]; +} +``` + +## Migration Guide + +### From flakeUrl to home + +1. **Update users.nix:** + ```diff + - flakeUrl = "github:user/dotfiles"; + + home = builtins.fetchGit { + + url = "https://github.com/user/dotfiles"; + + rev = "latest-commit-hash"; + + }; + ``` + +2. **Update your dotfiles repository:** + - Rename or ensure you have `home.nix` (not `flake.nix`) + - Change module signature from flake to simple module: + ```diff + - { inputs, outputs, ... }: + + { inputs, ... }: + { config, lib, pkgs, ... }: + ``` + +3. **Optional: Add nixos.nix** for system-level config + +4. **Test locally first:** + ```nix + home = /path/to/local/dotfiles; + ``` + +5. **Deploy:** + ```bash + nix flake check + ./deploy hostname + ``` + +## Benefits + +- **No Flakes Required**: Simpler for users unfamiliar with flakes +- **Explicit Versioning**: Pin to specific commits with `rev` +- **Faster Evaluation**: No flake evaluation overhead +- **Local Testing**: Easy to test with local paths +- **Flexibility**: Supports Git, paths, or inline configs +- **Reproducibility**: Commit hashes ensure exact versions + +## Templates + +See `/home/engr-ugaif/user-config-template/` for templates and detailed examples. diff --git a/flake.nix b/flake.nix index f5c2a6c..aaba908 100644 --- a/flake.nix +++ b/flake.nix @@ -105,5 +105,8 @@ modules = import ./installer/modules.nix { inherit inputs; }; in modules.homeModules or { }; + + # Templates for external configurations + templates = import ./templates; }; } diff --git a/hosts/default.nix b/hosts/default.nix index 352302d..62b0a89 100644 --- a/hosts/default.nix +++ b/hosts/default.nix @@ -38,18 +38,31 @@ let system ? "x86_64-linux", hostType, configOverrides ? { }, + externalModulePath ? null, }: let - # Load users.nix to find external user flakes + # Load users.nix to find external user modules pkgs = nixpkgs.legacyPackages.${system}; usersData = import ../users.nix { inherit pkgs; }; accounts = usersData.ugaif.users or { }; - # Extract flakeUrls and convert to modules - userFlakeModules = lib.mapAttrsToList ( + # Extract external user NixOS modules (if they exist) + # External user modules can optionally provide a nixos.nix file for system-level config + userNixosModules = lib.mapAttrsToList ( name: user: - if (user ? flakeUrl && user.flakeUrl != "") then - (builtins.getFlake user.flakeUrl).nixosModules.default + if (user ? home && user.home != null) then + let + homePath = + if builtins.isAttrs user.home && user.home ? outPath then + user.home.outPath + else + user.home; + nixosModulePath = homePath + "/nixos.nix"; + in + if (builtins.isPath homePath || (builtins.isString homePath && lib.hasPrefix "/" homePath)) && builtins.pathExists nixosModulePath then + import nixosModulePath { inherit inputs; } + else + { } else { } ) accounts; @@ -69,6 +82,13 @@ let else { }; + # External module from fetchGit/fetchurl + externalPathModule = + if externalModulePath != null then + import externalModulePath { inherit inputs; } + else + { }; + # Config override module - translate special keys to ugaif options overrideModule = { ... }: @@ -108,13 +128,14 @@ let }; allModules = - userFlakeModules + userNixosModules ++ [ typeModule overrideModule { networking.hostName = hostName; } ] - ++ lib.optional (configOverrides ? flakeUrl) externalFlakeModule; + ++ lib.optional (configOverrides ? flakeUrl) externalFlakeModule + ++ lib.optional (externalModulePath != null) externalPathModule; in { system = lib.nixosSystem { @@ -170,16 +191,52 @@ let lib.mapAttrsToList ( deviceKey: deviceConfig: let - # Merge: base config -> overrides -> device-specific config - mergedConfig = lib.recursiveUpdate (lib.recursiveUpdate baseConfig overrides) deviceConfig; + # Check if deviceConfig is a path/derivation (from fetchGit, fetchurl, etc.) + # fetchGit/fetchTarball return an attrset with outPath attribute + isExternalModule = + (builtins.isPath deviceConfig) + || (builtins.isString deviceConfig && lib.hasPrefix "/" deviceConfig) + || (lib.isDerivation deviceConfig) + || (builtins.isAttrs deviceConfig && deviceConfig ? outPath); + + # Extract the actual path from fetchGit/fetchTarball results + extractedPath = + if builtins.isAttrs deviceConfig && deviceConfig ? outPath then + deviceConfig.outPath + else + deviceConfig; + + # If external module, we use base config + overrides as the config + # and pass the module path separately + actualConfig = if isExternalModule then (lib.recursiveUpdate baseConfig overrides) else deviceConfig; + + # Merge: base config -> overrides -> device-specific config (only if not external module) + mergedConfig = + if isExternalModule then + actualConfig + else + lib.recursiveUpdate (lib.recursiveUpdate baseConfig overrides) deviceConfig; + # Check useHostPrefix from the merged config usePrefix = mergedConfig.ugaif.host.useHostPrefix or true; hostName = mkHostName prefix deviceKey usePrefix; + + # If external module, also add a default.nix path for import + externalModulePath = + if isExternalModule then + if builtins.isPath extractedPath then + extractedPath + "/default.nix" + else if lib.isDerivation extractedPath then + extractedPath + "/default.nix" + else + extractedPath + "/default.nix" + else + null; in { name = hostName; value = mkHost { - inherit hostName system hostType; + inherit hostName system hostType externalModulePath; configOverrides = mergedConfig; }; } diff --git a/hosts/user-config.nix b/hosts/user-config.nix index b2e2fe9..966d0c2 100644 --- a/hosts/user-config.nix +++ b/hosts/user-config.nix @@ -49,10 +49,16 @@ let 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)."; + home = lib.mkOption { + type = lib.types.nullOr (lib.types.oneOf [ lib.types.path lib.types.package lib.types.attrs ]); + default = null; + description = '' + External home-manager configuration. Can be: + - A path to a local module + - A fetchGit/fetchTarball result pointing to a repository + - An attribute set with home-manager configuration + Example: builtins.fetchGit { url = "https://github.com/user/dotfiles"; rev = "..."; } + ''; }; opensshKeys = lib.mkOption { type = lib.types.listOf lib.types.str; @@ -138,18 +144,37 @@ in name: user: { ... }: let - isExternal = user.flakeUrl != ""; + # Check if user has external home configuration + hasExternalHome = user.home != null; + + # Extract path from fetchGit/fetchTarball if needed + externalHomePath = + if hasExternalHome then + if builtins.isAttrs user.home && user.home ? outPath then + user.home.outPath + else + user.home + else + null; + + # Import external module if it's a path + externalHomeModule = + if externalHomePath != null && (builtins.isPath externalHomePath || (builtins.isString externalHomePath && lib.hasPrefix "/" externalHomePath)) then + import (externalHomePath + "/home.nix") { inherit inputs; } + else if builtins.isAttrs user.home && !(user.home ? outPath) then + user.home # Direct attrset configuration + else + { }; # Common imports based on flags commonImports = lib.optional user.useZshTheme ../sw/theme.nix ++ [ (import ../sw/nvim.nix { inherit user; }) ]; in - if isExternal then + if hasExternalHome then { - # External users: Only apply requested system modules. - # The external flake is responsible for home.username, home.packages, etc. - imports = commonImports; + # External users: Merge external config with common imports + imports = commonImports ++ [ externalHomeModule ]; } else { diff --git a/inventory.nix b/inventory.nix index 3054334..1c3e07b 100644 --- a/inventory.nix +++ b/inventory.nix @@ -43,6 +43,10 @@ # Convenience options: # ugaif.forUser = "username"; # Automatically adds user to extraUsers and sets wslUser for WSL # + # External modules (instead of config): + # Device values can be either a config attrset OR a fetchGit/fetchurl call + # that points to an external Nix module. The module will be imported and evaluated. + # # Examples: # "lab" = { devices = 3; }; # Quick: lab1, lab2, lab3 # "lab" = { count = 3; }; # Same as above @@ -56,6 +60,12 @@ # }; # "wsl" = { # devices."alice".ugaif.forUser = "alice123"; # Sets up for user alice123 + # }; + # "external" = { + # devices."remote" = builtins.fetchGit { # External module via Git + # url = "https://github.com/example/config"; + # rev = "abc123..."; + # }; # }; # ========== Lab Laptops ========== # Creates: nix-laptop1, nix-laptop2 # Both get hdh20267 user via overrides @@ -87,7 +97,10 @@ nix-lxc = { devices = { "nix-builder" = { }; - "usda-dash" = { }; + "usda-dash" = builtins.fetchGit { + url = "https://git.factory.uga.edu/MODEL/usda-dash-config.git"; + rev = "4491f7826824c41a8e5047c04b198040d397a219"; + }; }; overrides = { ugaif.host.useHostPrefix = false; @@ -105,4 +118,35 @@ # ========== Ephemeral/Netboot System ========== # Creates: nix-ephemeral1 nix-ephemeral.devices = 1; + + # ========== Example: External Module Configurations ========== + # Uncomment to use external modules from Git repositories: + # + # external-systems = { + # devices = { + # # Option 1: fetchGit with specific revision (recommended for reproducibility) + # "prod-server" = builtins.fetchGit { + # url = "https://github.com/example/server-config"; + # rev = "abc123def456..."; # Full commit hash + # ref = "main"; # Optional: branch/tag name + # }; + # + # # Option 2: fetchGit with latest from branch (less reproducible) + # "dev-server" = builtins.fetchGit { + # url = "https://github.com/example/server-config"; + # ref = "develop"; + # }; + # + # # Option 3: fetchTarball for specific release + # "test-server" = builtins.fetchTarball { + # url = "https://github.com/example/server-config/archive/v1.0.0.tar.gz"; + # sha256 = "sha256:0000000000000000000000000000000000000000000000000000"; + # }; + # + # # Option 4: Mix external module with local overrides + # # Note: The external module's default.nix should export a NixOS module + # # that accepts { inputs, ... } as parameters + # }; + # }; } + diff --git a/sw/updater.nix b/sw/updater.nix index ba3942b..3fd87e2 100644 --- a/sw/updater.nix +++ b/sw/updater.nix @@ -60,6 +60,11 @@ with lib; systemd.services.update-system = { enable = true; description = "System daemon to one-shot run the Nix updater from fleet flake as root"; + path = with pkgs; [ + git + nixos-rebuild + nix + ]; serviceConfig = { Type = "oneshot"; ExecStart = diff --git a/templates/default.nix b/templates/default.nix new file mode 100644 index 0000000..8b628e7 --- /dev/null +++ b/templates/default.nix @@ -0,0 +1,40 @@ +{ + system = { + path = ./system; + description = "External NixOS system configuration module"; + welcomeText = '' + # External System Configuration Template + + This template creates an external NixOS system configuration module + that can be referenced from nixos-systems/inventory.nix. + + ## Quick Start + + 1. Edit `default.nix` with your system configuration + 2. Commit to a Git repository + 3. Reference in inventory.nix using the `flakeUrl` field + + See README.md for detailed documentation. + ''; + }; + + user = { + path = ./user; + description = "External user home-manager configuration"; + welcomeText = '' + # User Configuration Template + + This template creates an external user configuration module + that can be referenced from nixos-systems/users.nix. + + ## Quick Start + + 1. Edit `home.nix` with your home-manager configuration + 2. (Optional) Edit `nixos.nix` for system-level configuration + 3. Commit to a Git repository + 4. Reference in users.nix using the `flakeUrl` field + + See README.md for detailed documentation. + ''; + }; +} diff --git a/templates/system/.gitignore b/templates/system/.gitignore new file mode 100644 index 0000000..ce7b4b1 --- /dev/null +++ b/templates/system/.gitignore @@ -0,0 +1,3 @@ +result +result-* +.direnv/ diff --git a/templates/system/README.md b/templates/system/README.md new file mode 100644 index 0000000..0e6d474 --- /dev/null +++ b/templates/system/README.md @@ -0,0 +1,99 @@ +# External System Module Template + +This directory contains a template for creating external system configuration modules that can be referenced from the main `nixos-systems` repository. + +## Overview + +External modules allow you to maintain system configurations in separate Git repositories and reference them from the main `nixos-systems/inventory.nix` file using `builtins.fetchGit` or `builtins.fetchTarball`. + +## Usage + +### 1. Create Your Module Repository + +Copy `default.nix` from this template to your own Git repository. Customize it with your system configuration. + +### 2. Reference It in inventory.nix + +```nix +{ + "my-system-type" = { + devices = { + "hostname" = builtins.fetchGit { + url = "https://github.com/your-org/your-config-repo"; + rev = "abc123def456..."; # Full commit hash for reproducibility + ref = "main"; # Optional: branch/tag name + }; + }; + }; +} +``` + +### 3. Module Structure + +Your `default.nix` must: +- Accept `{ inputs, ... }` as parameters (you'll receive the same flake inputs) +- Return a valid NixOS module with `{ config, lib, pkgs, ... }: { ... }` +- Export configuration under the `config` attribute + +## Examples + +### Simple Configuration Module + +```nix +{ inputs, ... }: + +{ config, lib, pkgs, ... }: + +{ + config = { + time.timeZone = "America/New_York"; + + environment.systemPackages = with pkgs; [ + vim + git + htop + ]; + + services.openssh.enable = true; + }; +} +``` + +### Advanced Module with Options + +```nix +{ inputs, ... }: + +{ config, lib, pkgs, ... }: + +{ + options.myorg.databaseUrl = lib.mkOption { + type = lib.types.str; + description = "Database connection URL"; + }; + + config = { + # Use the option + services.postgresql = { + enable = true; + # ... configuration using config.myorg.databaseUrl + }; + }; +} +``` + +## Benefits + +- **Separation of Concerns**: Keep specialized configurations in dedicated repositories +- **Reusability**: Share configurations across multiple NixOS fleets +- **Version Control**: Pin to specific commits for reproducibility +- **Team Ownership**: Different teams can maintain their own config repos +- **Security**: Private repositories for sensitive configurations + +## Integration with nixos-systems + +External modules are automatically integrated into the nixos-systems build: +- They receive the same flake inputs (nixpkgs, home-manager, etc.) +- They can use ugaif.* options if defined in the host type +- They are merged with local overrides and base configuration +- They work with all build methods (ISO, LXC, Proxmox, etc.) diff --git a/templates/system/default.nix b/templates/system/default.nix new file mode 100644 index 0000000..8e7bfde --- /dev/null +++ b/templates/system/default.nix @@ -0,0 +1,56 @@ +{ inputs, ... }: + +# ============================================================================ +# External System Module Template +# ============================================================================ +# This is a template for creating external system configuration modules +# that can be referenced from nixos-systems/inventory.nix using builtins.fetchGit +# +# Usage in inventory.nix: +# "my-type" = { +# devices = { +# "hostname" = builtins.fetchGit { +# url = "https://github.com/your-org/your-config-repo"; +# rev = "commit-hash"; +# }; +# }; +# }; +# +# This module will receive the same `inputs` flake inputs as the main +# nixos-systems configuration, allowing you to use nixpkgs, home-manager, etc. + +{ + config, + lib, + pkgs, + ... +}: + +{ + # ========== Module Options ========== + # Define any custom options your module needs + options = { + # Example: myorg.customOption = lib.mkOption { ... }; + }; + + # ========== Module Configuration ========== + config = { + # Your system configuration goes here + # This can include any NixOS options + + # Example: Set timezone + # time.timeZone = "America/New_York"; + + # Example: Install packages + # environment.systemPackages = with pkgs; [ + # vim + # git + # ]; + + # Example: Configure services + # services.openssh.enable = true; + + # Example: Use ugaif options if available from nixos-systems + # ugaif.users.myuser.enable = true; + }; +} diff --git a/templates/user/.gitignore b/templates/user/.gitignore new file mode 100644 index 0000000..ce7b4b1 --- /dev/null +++ b/templates/user/.gitignore @@ -0,0 +1,3 @@ +result +result-* +.direnv/ diff --git a/templates/user/README.md b/templates/user/README.md new file mode 100644 index 0000000..2845a78 --- /dev/null +++ b/templates/user/README.md @@ -0,0 +1,183 @@ +# User Configuration Template + +This directory contains templates for creating external user configuration modules that can be referenced from the main `nixos-systems/users.nix` file. + +## Overview + +External user modules allow users to maintain their personal configurations (dotfiles, packages, settings) in separate Git repositories and reference them from the main `nixos-systems` repository using `builtins.fetchGit`. + +## Structure + +``` +user-dotfiles-repo/ +├── home.nix # Required: Home-manager configuration +├── nixos.nix # Optional: System-level NixOS configuration +├── README.md # Documentation +└── dotfiles/ # Optional: Dotfiles to symlink +``` + +## Usage + +### 1. Create Your User Configuration Repository + +Copy the templates from this directory to your own Git repository: +- `home.nix` - Required for home-manager configuration +- `nixos.nix` - Optional for system-level configuration + +### 2. Reference It in users.nix + +```nix +{ + ugaif.users = { + myusername = { + description = "My Name"; + extraGroups = [ "wheel" "networkmanager" ]; + shell = pkgs.zsh; + + # Option 1: External module from Git + home = builtins.fetchGit { + url = "https://github.com/username/dotfiles"; + rev = "abc123def456..."; # Full commit hash for reproducibility + ref = "main"; # Optional: branch/tag name + }; + + # Option 2: Local path for testing + # home = /path/to/local/dotfiles; + + # Option 3: Inline configuration + # home = { + # home.packages = [ pkgs.vim ]; + # programs.git.enable = true; + # }; + }; + }; +} +``` + +### 3. Enable on Systems + +Enable the user in `inventory.nix`: + +```nix +{ + "my-system" = { + devices = { + "hostname" = { + extraUsers = [ "myusername" ]; + }; + }; + }; +} +``` + +## File Descriptions + +### home.nix (Required) + +This file contains your home-manager configuration. It must be a valid NixOS module that accepts `{ inputs, ... }` and returns a home-manager configuration. + +**Must export:** +- Home-manager options (programs.*, home.packages, etc.) + +**Receives:** +- `inputs` - Flake inputs (nixpkgs, home-manager, etc.) +- `config` - Home-manager config +- `pkgs` - Nixpkgs package set +- `osConfig` - Access to OS-level configuration + +### nixos.nix (Optional) + +This file contains system-level NixOS configuration. Only needed for: +- System services related to the user +- System packages requiring root +- Special permissions or system settings + +## Examples + +### Minimal home.nix + +```nix +{ inputs, ... }: + +{ config, lib, pkgs, ... }: + +{ + home.packages = with pkgs; [ + vim + git + htop + ]; + + programs.git = { + enable = true; + userName = "My Name"; + userEmail = "me@example.com"; + }; +} +``` + +### With Dotfiles + +```nix +{ inputs, ... }: + +{ config, lib, pkgs, ... }: + +{ + home.packages = with pkgs; [ ripgrep fd bat ]; + + # Symlink dotfiles + home.file.".bashrc".source = ./dotfiles/bashrc; + home.file.".vimrc".source = ./dotfiles/vimrc; + + programs.git = { + enable = true; + userName = "My Name"; + userEmail = "me@example.com"; + }; +} +``` + +### With System Configuration (nixos.nix) + +```nix +{ inputs, ... }: + +{ config, lib, pkgs, ... }: + +{ + # Add user to docker group + users.users.myusername.extraGroups = [ "docker" ]; + + # Install system package + environment.systemPackages = [ pkgs.docker ]; +} +``` + +## Integration Features + +External user modules: +- Receive the same flake inputs as nixos-systems +- Can use all home-manager options +- Optionally provide system-level configuration (nixos.nix) +- System zsh theme applied if `useZshTheme = true` (default) +- System nvim config applied if `useNvimPlugins = true` (default) +- Merged with inventory.nix user settings (groups, shell, etc.) + +## Development Workflow + +1. Create your user config repository with `home.nix` +2. Test locally: `home = /path/to/local/repo;` +3. Build: `nix build .#nixosConfigurations.hostname.config.system.build.toplevel` +4. Commit and push changes +5. Update users.nix with commit hash +6. Deploy to systems + +## Benefits + +- **Personal Ownership**: Users maintain their own configs +- **Version Control**: Track dotfile changes over time +- **Portability**: Use same config across multiple machines +- **Reproducibility**: Pin to specific commits +- **Privacy**: Use private repositories for personal settings +- **Separation**: Keep personal configs separate from system configs diff --git a/templates/user/home.nix b/templates/user/home.nix new file mode 100644 index 0000000..866a5f5 --- /dev/null +++ b/templates/user/home.nix @@ -0,0 +1,91 @@ +{ inputs, ... }: + +# ============================================================================ +# User Home Manager Configuration Template +# ============================================================================ +# This file provides home-manager configuration for a user. +# It will be imported into the NixOS system's home-manager configuration. +# +# Usage in users.nix: +# myusername = { +# description = "My Name"; +# home = builtins.fetchGit { +# url = "https://github.com/username/dotfiles"; +# rev = "commit-hash"; +# }; +# }; +# +# This module receives the same `inputs` flake inputs as the main +# nixos-systems configuration (nixpkgs, home-manager, etc.). + +{ + config, + lib, + pkgs, + osConfig, # Access to the OS-level config + ... +}: + +{ + # ========== Home Manager Configuration ========== + + # User identity (required) + home.username = lib.mkDefault config.home.username; # Set by system + home.homeDirectory = lib.mkDefault config.home.homeDirectory; # Set by system + home.stateVersion = lib.mkDefault "25.11"; + + # ========== Packages ========== + home.packages = with pkgs; [ + # Add your preferred packages here + # htop + # ripgrep + # fd + # bat + ]; + + # ========== Programs ========== + + # Git configuration + programs.git = { + enable = true; + userName = "Your Name"; + userEmail = "your.email@example.com"; + extraConfig = { + init.defaultBranch = "main"; + }; + }; + + # Zsh configuration + programs.zsh = { + enable = true; + # System theme is applied automatically if useZshTheme = true in users.nix + # Add your custom zsh config here + }; + + # Neovim configuration + # programs.neovim = { + # enable = true; + # # System nvim config is applied automatically if useNvimPlugins = true + # # Add your custom neovim config here + # }; + + # ========== Shell Environment ========== + + home.sessionVariables = { + EDITOR = "vim"; + # Add your custom environment variables + }; + + # ========== Dotfiles ========== + + # You can manage dotfiles with home.file + # home.file.".bashrc".source = ./dotfiles/bashrc; + # home.file.".vimrc".source = ./dotfiles/vimrc; + + # Or use programs.* options for better integration + + # ========== XDG Configuration ========== + + xdg.enable = true; + # xdg.configFile."app/config.conf".source = ./config/app.conf; +} diff --git a/templates/user/nixos.nix b/templates/user/nixos.nix new file mode 100644 index 0000000..afd98aa --- /dev/null +++ b/templates/user/nixos.nix @@ -0,0 +1,47 @@ +{ inputs, ... }: + +# ============================================================================ +# User NixOS System Configuration (Optional) +# ============================================================================ +# This file provides system-level NixOS configuration for a user. +# It's optional - most user configuration should go in home.nix. +# +# Use this for: +# - System-level services that depend on the user (e.g., user systemd services) +# - Special system permissions or configurations +# - Installing system packages that require root +# +# This module receives the same `inputs` flake inputs as the main +# nixos-systems configuration. + +{ + config, + lib, + pkgs, + ... +}: + +{ + # ========== System Configuration ========== + + # Example: Enable a system service for this user + # systemd.services.my-user-service = { + # description = "My User Service"; + # wantedBy = [ "multi-user.target" ]; + # serviceConfig = { + # Type = "oneshot"; + # User = "myusername"; + # ExecStart = "${pkgs.bash}/bin/bash -c 'echo Hello'"; + # }; + # }; + + # Example: Install system-wide packages needed by this user + # environment.systemPackages = with pkgs; [ + # docker + # ]; + + # Example: Add user to additional groups + # users.users.myusername.extraGroups = [ "docker" ]; + + # Most configuration should be in home.nix instead of here +} diff --git a/users.nix b/users.nix index 19bf945..70f9d95 100644 --- a/users.nix +++ b/users.nix @@ -10,6 +10,16 @@ # Define the users here using the new option # To generate a password hash, run: mkpasswd -m sha-512 # Set enabled = true on systems where the user should exist + # + # External Home Configuration: + # Users can specify external home-manager configuration via the 'home' attribute: + # home = builtins.fetchGit { url = "..."; rev = "..."; }; + # home = /path/to/local/config; + # home = { home.packages = [ ... ]; }; # Direct attrset + # + # External repositories should contain: + # - home.nix (required): Home-manager configuration + # - nixos.nix (optional): System-level NixOS configuration ugaif.users = { root = { isNormalUser = false; @@ -38,8 +48,12 @@ ]; homePackages = [ pkgs.ghostty ]; shell = pkgs.zsh; - # Example of using an external flake for configuration: - # flakeUrl = "github:hdh20267/dotfiles"; + # Example of using an external module for home-manager configuration: + # home = builtins.fetchGit { + # url = "https://github.com/hdh20267/dotfiles"; + # rev = "abc123..."; + # }; + # This expects a home.nix file in the repository with home-manager config # enable = false by default, set to true per-system }; sv22900 = {