Files
athenix/docs/EXTERNAL_MODULES.md
2025-12-17 09:25:51 -05:00

9.1 KiB

External Configuration Modules

This guide explains how to use external modules for system and user configurations in nixos-systems.

Table of Contents

Overview

External modules allow you to maintain configurations in separate Git repositories and reference them from inventory.nix (for systems) or users.nix (for users).

Benefits:

  • Separation: Keep configs in separate repositories
  • Versioning: Pin to specific commits for reproducibility
  • Reusability: Share configurations across deployments
  • Flexibility: Mix external modules with local overrides

System Modules

External system modules provide complete NixOS configurations for hosts.

Usage in inventory.nix

nix-lxc = {
  devices = {
    # Traditional inline configuration
    "local-server" = {
      ugaif.users.admin.enable = true;
      services.nginx.enable = true;
    };
    
    # External module from Git
    "remote-server" = builtins.fetchGit {
      url = "https://github.com/org/server-config";
      rev = "abc123...";  # Pin to specific commit
    };
  };
};

External Repository Structure

server-config/
├── default.nix    # Required: NixOS module
└── README.md      # Optional: Documentation

default.nix:

{ inputs, ... }:
{ config, lib, pkgs, ... }:
{
  # Your NixOS configuration
  services.nginx = {
    enable = true;
    virtualHosts."example.com" = {
      root = "/var/www";
    };
  };
  
  # Use ugaif namespace options
  ugaif.users.admin.enable = true;
  ugaif.sw.type = "headless";
}

What External Modules Receive

  • inputs - All flake inputs (nixpkgs, home-manager, etc.)
  • config - Full NixOS configuration
  • lib - Nixpkgs library functions
  • pkgs - Package set

Module Integration Order

When a host is built, modules are loaded in this order:

  1. User NixOS modules (from users.nix - nixos.nix files)
  2. Host type module (from hosts/types/)
  3. Configuration overrides (from inventory.nix)
  4. Hostname assignment
  5. External system module (if using builtins.fetchGit)

Later modules can override earlier ones using standard NixOS module precedence.

Template

Create a new system module:

nix flake init -t github:UGA-Innovation-Factory/nixos-systems#system

See templates/system/ for the complete template.

User Modules

External user modules provide home-manager configurations (dotfiles, packages, programs).

Usage in users.nix

ugaif.users = {
  myuser = {
    description = "My Name";
    extraGroups = [ "wheel" "networkmanager" ];
    hashedPassword = "$6$...";
    
    # External home-manager configuration
    home = builtins.fetchGit {
      url = "https://github.com/username/dotfiles";
      rev = "abc123...";
    };
  };
};

External Repository Structure

dotfiles/
├── home.nix     # Required: Home-manager config
├── nixos.nix    # Optional: System-level config
└── dotfiles/    # Optional: Actual dotfiles
    ├── bashrc
    └── vimrc

home.nix (required):

{ inputs, ... }:
{ config, lib, pkgs, osConfig, ... }:
{
  # Home-manager configuration
  home.packages = with pkgs; [ vim git htop ];
  
  programs.git = {
    enable = true;
    userName = "My Name";
    userEmail = "me@example.com";
  };
  
  # Manage dotfiles
  home.file.".bashrc".source = ./dotfiles/bashrc;
}

nixos.nix (optional):

{ inputs, ... }:
{ config, lib, pkgs, ... }:
{
  # System-level configuration for this user
  users.users.myuser.extraGroups = [ "docker" ];
  environment.systemPackages = [ pkgs.docker ];
}

What User Modules Receive

In home.nix:

  • inputs - Flake inputs (nixpkgs, home-manager, etc.)
  • config - Home-manager configuration
  • lib - Nixpkgs library functions
  • pkgs - Package set
  • osConfig - OS-level configuration (read-only)

In nixos.nix:

  • inputs - Flake inputs
  • config - NixOS configuration
  • lib - Nixpkgs library functions
  • pkgs - Package set

User Options in users.nix

username = {
  # Identity
  description = "Full Name";
  
  # External configuration
  home = builtins.fetchGit { ... };
  
  # System settings
  extraGroups = [ "wheel" "networkmanager" ];
  hashedPassword = "$6$...";
  opensshKeys = [ "ssh-ed25519 ..." ];
  shell = pkgs.zsh;
  
  # Theme integration
  useZshTheme = true;      # Apply system zsh theme (default: true)
  useNvimPlugins = true;   # Apply system nvim config (default: true)
  
  # Enable on specific systems (see docs/INVENTORY.md)
  enable = false;  # Set in inventory.nix via ugaif.users.username.enable
};

Template

Create a new user module:

nix flake init -t github:UGA-Innovation-Factory/nixos-systems#user

See templates/user/ for the complete template.

Fetch Methods

Pin to a specific commit for reproducibility:

builtins.fetchGit {
  url = "https://github.com/user/repo";
  rev = "abc123def456...";  # Full commit hash (40 characters)
  ref = "main";              # Optional: branch name
}

Finding the commit hash:

# Latest commit on main branch
git ls-remote https://github.com/user/repo main

# Or from a local clone
git rev-parse HEAD

fetchGit with Branch (Less Reproducible)

Always fetches latest from branch:

builtins.fetchGit {
  url = "https://github.com/user/repo";
  ref = "develop";
}

⚠️ Warning: Builds may not be reproducible as the branch HEAD can change.

fetchTarball (For Releases)

Download specific release archives:

builtins.fetchTarball {
  url = "https://github.com/user/repo/archive/v1.0.0.tar.gz";
  sha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
}

Get the hash:

nix-prefetch-url --unpack https://github.com/user/repo/archive/v1.0.0.tar.gz

Local Path (For Testing)

Use local directories during development:

/home/username/dev/my-config

# Or relative to repository
./my-local-config

⚠️ Warning: Only for testing. Use Git-based methods for production.

Templates

System Module Template

# Initialize in new directory
mkdir my-server-config
cd my-server-config
nix flake init -t github:UGA-Innovation-Factory/nixos-systems#system

See templates/system/README.md for detailed usage.

User Module Template

# Initialize in new directory
mkdir my-dotfiles
cd my-dotfiles
nix flake init -t github:UGA-Innovation-Factory/nixos-systems#user

See templates/user/README.md for detailed usage.

Integration Details

Detection Logic

The system automatically detects external modules when a device or user value is:

  • A path (builtins.isPath)
  • A string starting with / (absolute path)
  • A derivation (lib.isDerivation)
  • An attrset with outPath attribute (result of fetchGit/fetchTarball)

System Module Integration

External system modules are imported and merged into the NixOS configuration:

import externalModulePath { inherit inputs; }

They can use all standard NixOS options plus ugaif.* namespace options.

User Module Integration

External user modules are loaded separately for home-manager (home.nix) and NixOS (nixos.nix if it exists):

Home-manager:

import (externalHomePath + "/home.nix") { inherit inputs; }

NixOS (optional):

import (externalHomePath + "/nixos.nix") { inherit inputs; }

Combining External and Local Config

You can mix external modules with local overrides:

nix-lxc = {
  devices = {
    "server" = builtins.fetchGit {
      url = "https://github.com/org/base-config";
      rev = "abc123...";
    };
  };
  overrides = {
    # Apply to all devices, including external ones
    ugaif.users.admin.enable = true;
    networking.firewall.allowedTCPPorts = [ 80 443 ];
  };
};

Examples

Minimal System Module

default.nix:

{ inputs, ... }:
{ config, lib, pkgs, ... }:
{
  ugaif.sw.type = "headless";
  services.nginx.enable = true;
}

Minimal User Module

home.nix:

{ inputs, ... }:
{ config, lib, pkgs, ... }:
{
  home.packages = with pkgs; [ vim git ];
}

Full User Module with Dotfiles

dotfiles/
├── home.nix
├── nixos.nix
└── config/
    ├── bashrc
    ├── vimrc
    └── gitconfig

home.nix:

{ inputs, ... }:
{ config, lib, pkgs, ... }:
{
  home.packages = with pkgs; [ ripgrep fd bat ];
  
  home.file = {
    ".bashrc".source = ./config/bashrc;
    ".vimrc".source = ./config/vimrc;
    ".gitconfig".source = ./config/gitconfig;
  };
}

See Also