11 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" = {
athenix.users.admin.enable = true;
services.nginx.enable = true;
};
# External module from Git
"remote-server" = builtins.fetchGit {
url = "https://git.factory.uga.edu/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 athenix namespace options
athenix.users.admin.enable = true;
athenix.sw.type = "headless";
}
What External Modules Receive
inputs- All flake inputs (nixpkgs, home-manager, etc.)config- Full NixOS configurationlib- Nixpkgs library functionspkgs- Package set
Module Integration Order
When a host is built, modules are loaded in this order:
- User NixOS modules (from
users.nix-nixos.nixfiles) - Host type module (from
hosts/types/) - Configuration overrides (from
inventory.nix) - Hostname assignment
- 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 git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#system
See templates/system/ for the complete template.
User Modules
External user modules provide home-manager configurations (dotfiles, packages, programs).
Usage in users.nix
athenix.users = {
# External user module (dotfiles, home-manager, and user options)
myuser = builtins.fetchGit {
url = "https://git.factory.uga.edu/username/dotfiles";
rev = "abc123...";
};
# Inline user definition
inlineuser = {
description = "Inline User";
extraGroups = [ "wheel" ];
shell = pkgs.zsh;
hashedPassword = "$6$...";
};
};
External Repository Structure
dotfiles/
├── user.nix # Required: User options AND home-manager config
├── nixos.nix # Optional: System-level config
└── config/ # Optional: Actual dotfiles
├── bashrc
└── vimrc
user.nix (required):
{ inputs, ... }:
{ config, lib, pkgs, osConfig ? null, ... }:
{
# ========== User Account Configuration ==========
athenix.users.myusername = {
description = "Your Full Name";
shell = pkgs.zsh;
hashedPassword = "!";
opensshKeys = [ "ssh-ed25519 AAAA..." ];
useZshTheme = true;
useNvimPlugins = true;
};
# ========== Home Manager Configuration ==========
# Packages
home.packages = with pkgs; [
vim
git
htop
] ++ lib.optional (osConfig.athenix.sw.type or null == "desktop") firefox;
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 user.nix:
inputs- Flake inputs (nixpkgs, home-manager, etc.)config- Home-manager configurationlib- Nixpkgs library functionspkgs- Package setosConfig- OS-level configuration (read-only)
In nixos.nix:
inputs- Flake inputsconfig- NixOS configurationlib- Nixpkgs library functionspkgs- Package set
User Options in users.nix
username = {
# Identity
description = "Full Name";
# External configuration
external = 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 athenix.users.username.enable
};
Template
Create a new user module:
nix flake init -t git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#user
See templates/user/ for the complete template.
Fetch Methods
Recommended: fetchGit with Revision
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 git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#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 git+https://git.factory.uga.edu/UGA-Innovation-Factory/athenix.git#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
outPathattribute (result offetchGit/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 athenix.* namespace options.
User Module Integration
External user modules are loaded in two contexts:
User options (NixOS module context):
import (externalPath + "/user.nix") { inherit inputs; }
# Evaluated as NixOS module to extract athenix.users.<username> options
Home-manager configuration:
import (externalPath + "/user.nix") { inherit inputs; }
# Imported into home-manager for home.*, programs.*, services.* options
System-level config (optional):
import (externalPath + "/nixos.nix") { inherit inputs; }
# If present, imported as NixOS module for system-level configuration
Combining External and Local Config
You can mix external modules with local overrides:
nix-lxc = {
devices = {
"server" = builtins.fetchGit {
url = "https://git.factory.uga.edu/org/base-config";
rev = "abc123...";
};
};
overrides = {
# Apply to all devices, including external ones
athenix.users.admin.enable = true;
networking.firewall.allowedTCPPorts = [ 80 443 ];
};
};
Minimal User Module
user.nix:
{ inputs, ... }:
{ config, lib, pkgs, osConfig ? null, ... }:
{
# User account options
athenix.users.myusername = {
description = "My Name";
shell = pkgs.zsh;
hashedPassword = "!";
};
# Home-manager config
home.packages = with pkgs; [ vim git ];
}
Full User Module with Dotfiles
dotfiles/
├── user.nix
├── nixos.nix
└── config/
├── bashrc
├── vimrc
└── gitconfig
user.nix:
{ inputs, ... }:
{ config, lib, pkgs, osConfig ? null, ... }:
{
# User account configuration
athenix.users.myusername = {
description = "My Full Name";
shell = pkgs.zsh;
extraGroups = [ "wheel" "networkmanager" ];
hashedPassword = "!";
opensshKeys = [ "ssh-ed25519 AAAA..." ];
useZshTheme = true;
useNvimPlugins = true;
};
# Home-manager configuration
home.packages = with pkgs; [
ripgrep
fd
bat
] ++ lib.optional (osConfig.athenix.sw.type or null == "desktop") firefox;
programs.git = {
enable = true;
userName = "My Full Name";
userEmail = "me@example.com";
extraConfig.init.defaultBranch = "main";
};
home.file = {
".bashrc".source = ./config/bashrc;
".vimrc".source = ./config/vimrc;
".gitconfig".source = ./config/gitconfig;
};
}
See Also
- INVENTORY.md - Host configuration guide
- USER_CONFIGURATION.md - User management guide
- NAMESPACE.md - Configuration options reference
- templates/system/ - System module template
- templates/user/ - User module template
- README.md - Main documentation