- Update NAMESPACE.md: filesystem.device and swapSize defaults now null - Update README.md: add 'Using Athenix as a Library' section with lib.mkFleet - Update copilot-instructions.md: reflect new directory structure and defaults - Update EXTERNAL_MODULES.md: correct paths from variants/ and glue/ to hw/ and fleet/ - Update PROXMOX_LXC.md: update hardware type path reference
11 KiB
External Configuration Modules
Guide to using external modules for system and user configurations.
Table of Contents
Overview
External modules allow you to maintain configurations in separate Git repositories and reference them from Athenix.
Benefits:
- Separation - Keep complex configs in separate repositories
- Reproducibility - Pin specific commits for deterministic builds
- Reusability - Share configurations across multiple deployments
- Flexibility - Mix external modules with local configuration
- Ownership - Users maintain their own dotfiles
System Modules
External system modules provide host-specific NixOS configurations.
Usage
In inventory.nix, reference an external module using the external field:
nix-lxc = {
devices = {
# Inline configuration (traditional method)
"local-server" = {
athenix.sw.type = "headless";
services.nginx.enable = true;
};
# External module (lazy evaluation - fetched only when building this host)
"remote-server".external = builtins.fetchGit {
url = "https://git.factory.uga.edu/org/server-config";
rev = "abc123def456..."; # Must pin to specific commit
};
# External module with additional local config
"mixed-server" = {
external = builtins.fetchGit {
url = "https://git.factory.uga.edu/org/server-config";
rev = "abc123def456...";
};
# Additional local overrides
athenix.users.admin.enable = true;
services.openssh.permitRootLogin = "no";
};
};
};
Key Features:
- Lazy Evaluation: External modules are only fetched when building the specific host
- Efficient Rebuilds: Other hosts can be rebuilt without fetching unrelated external modules
- Submodule Support: Works with Git submodules without affecting other hosts
Repository Structure
server-config/
├── default.nix # Required: NixOS module
├── README.md # Recommended: Documentation
└── optional/
├── config/ # Optional: Configuration files
└── scripts/ # Optional: Helper scripts
Module Content (default.nix)
# The module receives inputs and standard NixOS module parameters
{ inputs, ... }:
{ config, lib, pkgs, ... }:
{
# Your NixOS configuration
# Use any standard NixOS option or athenix.* options
services.nginx = {
enable = true;
virtualHosts."example.com" = {
root = "/var/www";
forceSSL = true;
enableACME = true;
};
};
# Use athenix options
athenix.sw.type = "headless";
athenix.sw.extraPackages = with pkgs; [ git htop ];
# Standard NixOS configuration
networking.firewall.allowedTCPPorts = [ 80 443 ];
services.openssh.enable = true;
}
What System Modules Receive
inputs- All flake inputs (nixpkgs, home-manager, disko, etc.)config- Current NixOS configuration (read/write)lib- Nixpkgs library functionspkgs- Package set
Configuration Order
When a host is built, modules load in this order:
- Hardware type module (from
hw/nix-*.nix) - Common system configuration (from
fleet/common.nix) - Software type module (from
sw/{type}/) - User NixOS modules (from
users.nix-nixos.nixfiles) - Device-specific overrides (from
inventory.nix) - External system module (if present)
Each later module can override earlier ones using standard NixOS precedence rules.
User Modules
External user modules provide home-manager configurations (dotfiles, environment setup).
Usage
In users.nix, reference an external user module:
athenix.users = {
# External user module
myuser.external = builtins.fetchGit {
url = "https://git.factory.uga.edu/username/dotfiles";
rev = "abc123def456..."; # Pin to specific commit
};
# Inline user definition
otheruser = {
description = "Other User";
extraGroups = [ "wheel" ];
shell = pkgs.zsh;
hashedPassword = "$6$...";
};
};
Then enable on hosts in inventory.nix:
nix-laptop = {
devices = 5;
overrides.athenix.users.myuser.enable = true;
};
Repository Structure
my-dotfiles/
├── user.nix # Required: User options + home-manager config
├── nixos.nix # Optional: System-level configuration
├── README.md # Recommended: Documentation
└── config/ # Optional: Your actual dotfiles
├── zshrc
├── vimrc
├── nvim/
└── ...
user.nix (Required)
Provides both user account settings AND home-manager configuration:
# Receives { inputs } and standard home-manager module parameters
{ inputs, ... }:
{ config, lib, pkgs, osConfig ? null, ... }:
{
# ========== User Account Configuration ==========
# These options define the user account itself
athenix.users.myusername = {
description = "My Full Name";
extraGroups = [ "wheel" "docker" ];
shell = pkgs.zsh;
hashedPassword = "!"; # SSH keys only
opensshKeys = [
"ssh-ed25519 AAAA... user@laptop"
];
useZshTheme = true;
useNvimPlugins = true;
};
# ========== Home Manager Configuration ==========
# User environment, packages, and dotfiles
# Packages
home.packages = with pkgs; [
vim
git
ripgrep
fzf
] ++ lib.optional (osConfig.athenix.sw.type or null == "desktop") firefox;
# Programs
programs.git = {
enable = true;
userName = "My Name";
userEmail = "me@example.com";
extraConfig = {
init.defaultBranch = "main";
core.editor = "vim";
};
};
programs.zsh = {
enable = true;
initExtra = ''
# Your Zsh configuration
export EDITOR=vim
'';
};
# Manage dotfiles
home.file.".zshrc".source = ./config/zshrc;
home.file.".vimrc".source = ./config/vimrc;
home.file.".config/nvim".source = ./config/nvim;
# Services
services.gpg-agent.enable = true;
}
nixos.nix (Optional)
System-level configuration for this user (rarely needed):
{ inputs, ... }:
{ config, lib, pkgs, ... }:
{
# System-level configuration
# Only needed if the user requires specific system-wide settings
users.users.myusername.extraGroups = [ "docker" ];
environment.systemPackages = [ pkgs.docker ];
# Security settings
security.sudo.extraRules = [{
users = [ "myusername" ];
commands = [{
command = "/usr/bin/something";
options = [ "NOPASSWD" ];
}];
}];
}
What User Modules Receive
In user.nix:
inputs- All flake inputs (nixpkgs, home-manager, etc.)config- Home-manager configuration (read/write)lib- Nixpkgs library functionspkgs- Package setosConfig- OS configuration (read-only) - useful for conditional setup
In nixos.nix:
inputs- Flake inputsconfig- NixOS configuration (read/write)lib- Nixpkgs library functionspkgs- Package set
Conditional Setup Example
Use osConfig to conditionally set up dotfiles based on the system type:
# In user.nix
{ inputs, ... }:
{ config, lib, pkgs, osConfig ? null, ... }:
{
athenix.users.myuser = { /* ... */ };
# Install Firefox only on desktop systems
home.packages = with pkgs; [
ripgrep
] ++ lib.optional (osConfig.athenix.sw.type or null == "desktop") firefox;
# Different shell config per system
programs.zsh.initExtra = ''
${lib.optionalString (osConfig.athenix.sw.type or null == "headless") "
# Headless-only settings
"}
'';
}
Fetch Methods
builtins.fetchGit (Recommended)
Pin to a specific Git revision:
builtins.fetchGit {
url = "https://git.factory.uga.edu/username/dotfiles";
rev = "abc123def456..."; # Required: specific commit hash
}
Advantages:
- Reproducible (pinned to exact commit)
- Works with any Git repository
- Supports SSH or HTTPS URLs
Important: Always specify rev (commit hash) for reproducibility. Don't use branches which can change.
builtins.fetchTarball
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:
# users.nix
athenix.users.myuser.external = /home/user/my-dotfiles;
# inventory.nix
nix-laptop = {
devices = {
"dev".athenix.users.myuser.enable = true;
};
};
Note: Only works if the path exists on the machine running nix flake check or nix build.
Creating External Modules
System Module Template
Create a new system module repository from the template:
nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#system
This creates:
my-system-config/
├── flake.nix # Optional: for testing standalone
├── default.nix # Your NixOS module
└── README.md # Documentation
User Module Template
Create a new user module repository:
nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#user
This creates:
my-dotfiles/
├── flake.nix # Optional: for testing standalone
├── user.nix # User options + home-manager config
├── nixos.nix # Optional: system-level config
└── README.md # Documentation
Testing External Modules
Test your external module locally before pushing:
# In your module repository
cd /path/to/my-module
# Test the Nix syntax
nix flake check
Best Practices
1. Always Pin to Specific Commits
❌ Wrong - using branch names:
builtins.fetchGit {
url = "https://git.factory.uga.edu/username/dotfiles";
# No rev specified or using "main"
}
✅ Correct - using commit hash:
builtins.fetchGit {
url = "https://git.factory.uga.edu/username/dotfiles";
rev = "abc123def456789...";
}
2. Keep External Modules Focused
Each external module should have a clear purpose:
- User dotfiles (one repo per user)
- System service configuration (one repo per service/cluster)
- Hardware-specific config (one repo per hardware setup)
3. Document Your Modules
Include a README with:
- What the module configures
- Required dependencies
- Usage examples
- Configuration options
4. Use Semantic Versioning
Tag releases in Git:
git tag v1.0.0
git push origin v1.0.0
Reference specific versions:
builtins.fetchGit {
url = "https://git.factory.uga.edu/org/server-config";
rev = "v1.0.0"; # Can use tags too
}
5. Test Before Updating Pins
When updating commit hashes:
# Test new revision locally
nix flake update
# Validate all configurations
nix flake check --show-trace
# Only commit after validation
git add . && git commit -m "Update module versions"
See Also
- USER_CONFIGURATION.md - User management
- INVENTORY.md - Host configuration
- NAMESPACE.md - Configuration options
- README.md - Main documentation
- templates/user/ - User module template
- templates/system/ - System module template