UGA Innovation Factory - NixOS Systems
This repository contains the NixOS configuration for the Innovation Factory's fleet of laptops, desktops, and surface tablets. It provides a declarative, reproducible system configuration using Nix flakes.
Table of Contents
- Repository Structure
- Configuration Namespace
- Prerequisites
- Quick Start
- Building Artifacts
- Configuration Guide
- External Flake Templates
- Development
Repository Structure
flake.nix: The entry point for the configuration.inventory.nix: Defines the fleet inventory (host types, counts, and device-specific overrides).users.nix: Defines user accounts, passwords, and package sets.hosts/: Contains the logic for generating host configurations and hardware-specific types.sw/: Software modules (Desktop, Kiosk, Python, Neovim, etc.).
Configuration Namespace
All UGA Innovation Factory-specific NixOS options are organized under the ugaif namespace to clearly distinguish them from standard NixOS options. The main option groups are:
-
ugaif.host: Hardware and host-level configurationugaif.host.filesystem: Disk device and swap size settingsugaif.host.buildMethods: Supported artifact build methods (ISO, LXC, etc.)ugaif.host.wsl: WSL-specific configuration
-
ugaif.sw: Software and system type configurationugaif.sw.enable: Enable the software configuration moduleugaif.sw.type: System type (desktop,tablet-kiosk,headless,stateless-kiosk)ugaif.sw.kioskUrl: URL for kiosk mode browsersugaif.sw.python: Python development tools settingsugaif.sw.remoteBuild: Remote build configuration
-
ugaif.users: User account managementugaif.users.accounts: User account definitionsugaif.users.enabledUsers: List of users enabled on the systemugaif.users.shell: Default shell for users
Prerequisites
To work with this repository on a non-NixOS system (like macOS or another Linux distro), you need to install Nix. We recommend the Determinate Systems installer for a reliable and feature-complete setup (including Flakes support out of the box).
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
Quick Start
For End Users: Updating Your System
The easiest way to update your system is using the included update-system utility:
update-system
This command:
- Pulls the latest configuration from GitHub
- Rebuilds the system with any changes
- Automatically uses remote builders if you're on a Surface tablet
If you use external flakes (personal dotfiles), add the --impure flag:
update-system --impure
For Administrators: Managing the Fleet
Applying Configuration Changes
After modifying files in this repository:
# Test the configuration builds
nix flake check
# Push changes to GitHub
git add .
git commit -m "Description of changes"
git push
# Users can then run: update-system
Manual Rebuilds
For testing or emergency fixes:
# Rebuild current host
sudo nixos-rebuild switch --flake .
# Rebuild specific host
sudo nixos-rebuild switch --flake .#nix-laptop1
# Test without switching
sudo nixos-rebuild test --flake .#nix-laptop1
Updating Dependencies
Update nixpkgs, home-manager, and other flake inputs:
# Update all inputs
nix flake update
# Update specific input
nix flake lock --update-input nixpkgs
# After updating, test and commit the new flake.lock
git add flake.lock
git commit -m "Update flake inputs"
Building Artifacts (ISOs, LXC, Proxmox)
You can generate installation media and virtual machine images directly from this flake.
Installer ISOs
To build an auto-install ISO for a specific host (e.g., nix-laptop1):
nix build github:UGA-Innovation-Factory/nixos-systems#installer-iso-nix-laptop1
To speed up the build by offloading to a powerful build server (e.g., nix-builder), use the --builders flag:
nix build github:UGA-Innovation-Factory/nixos-systems#installer-iso-nix-laptop1 \
--builders "ssh://engr-ugaif@nix-builder x86_64-linux - 16 1 big-parallel"
The resulting ISO will be in result/iso/.
LXC / Proxmox Images
For hosts configured as containers (e.g., nix-lxc1), you can build LXC tarballs or Proxmox VMA archives:
# Build LXC tarball
nix build .#lxc-nix-lxc1
# Build Proxmox VMA
nix build .#proxmox-nix-lxc1
Configuration Guide
User Management
Adding a New User
- Open
users.nix. - Add a new entry to
ugaif.users.accounts:
ugaif.users.accounts = {
# ... existing users ...
newuser = {
description = "New User Name";
extraGroups = [ "networkmanager" "wheel" ];
hashedPassword = "$6$..."; # Generate with: mkpasswd -m sha-512
opensshKeys = [ "ssh-ed25519 AAAA..." ];
};
};
- Generate a hashed password using
mkpasswd -m sha-512(requireswhoispackage). - Commit and push the changes.
Note: Hashed passwords are for shared credentials only. For personal secrets, use external secret management.
Assigning Users to Hosts
By default, only root and engr-ugaif are enabled on all systems. To enable additional users on specific devices:
- Open
inventory.nix. - Locate the host type (e.g.,
nix-laptop). - Add the user to the device's
extraUserslist:
nix-laptop = {
count = 2;
devices = {
"1".extraUsers = [ "newuser" "hdh20267" ];
};
};
Using External Flakes for User Configuration
Users can manage their own dotfiles and configuration in a separate flake repository. This allows full control over shell configuration, editor settings, and Home Manager modules.
Security Note: External flakes run with the same privileges as the system configuration. Only use trusted flakes and pin to specific commits.
To enable this:
- Open
users.nix. - Set the
flakeUrlfor the user:
hdh20267 = {
description = "User Name";
extraGroups = [ "networkmanager" "wheel" ];
hashedPassword = "$6$...";
flakeUrl = "github:hdh20267/dotfiles";
# Optional: Disable system defaults
useZshTheme = false; # Manage your own Zsh config
useNvimPlugins = false; # Manage your own Neovim config
};
The external flake must provide a nixosModules.default output. See User Flake Template below for an example.
Host Configuration
Adding a New Host
To add more devices of an existing type:
- Open
inventory.nix. - Increment the
countfor the host type:
nix-laptop.count = 3; # Creates nix-laptop1, nix-laptop2, nix-laptop3
Device-Specific Configuration Overrides
You can customize individual devices in inventory.nix using either shortcut keys or direct configuration.
Shortcut Keys (for common settings):
extraUsers→ Setsugaif.users.enabledUsershostname→ Sets a custom hostname (default:{type}{number})buildMethods→ Setsugaif.host.buildMethodswslUser→ Setsugaif.host.wsl.userflakeUrl→ Imports an external system flake
Direct Configuration (using the ugaif namespace or standard NixOS options):
nix-laptop = {
count = 2;
devices = {
"1" = {
# Shortcut keys
extraUsers = [ "hdh20267" ];
hostname = "laptop-special";
# UGAIF options
ugaif.host.filesystem.swapSize = "64G";
ugaif.sw.extraPackages = with pkgs; [ docker vim ];
# Standard NixOS options
networking.firewall.enable = false;
services.openssh.enable = true;
};
};
};
Customizing Kiosk URLs for Surface Tablets
Surface tablets run in kiosk mode with a full-screen Chromium browser. Set the URL per-device:
nix-surface = {
count = 3;
devices = {
"1".ugaif.sw.kioskUrl = "https://ha.factory.uga.edu/dashboard-1";
"2".ugaif.sw.kioskUrl = "https://ha.factory.uga.edu/dashboard-2";
};
};
Using External Flakes for System Configuration
For complex system customizations (Docker, custom services, hardware tweaks), use an external flake:
nix-laptop = {
count = 2;
devices = {
"2".flakeUrl = "github:myuser/my-system-config";
};
};
The external flake must provide a nixosModules.default output. See System Flake Template below for an example.
External Flake Templates
If you're creating a flake to use with flakeUrl, use these templates as starting points.
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.
User Flake (for users.nix)
Use this template for user-specific dotfiles, shell configuration, Home Manager modules, and overriding user account settings.
{
description = "My User Configuration";
# No inputs needed! We use the system's packages.
outputs = { self }: {
# This output is what nixos-systems looks for
nixosModules.default = { pkgs, lib, ... }: {
# 1. Override System-Level User Settings
ugaif.users.accounts.hdh20267 = {
shell = pkgs.fish;
extraGroups = [ "docker" ];
# Optional: Disable system defaults if you manage your own
useZshTheme = false;
useNvimPlugins = false;
};
# Enable programs needed for the shell
programs.fish.enable = true;
# 2. Define Home Manager Configuration
home-manager.users.hdh20267 = { pkgs, ... }: {
home.stateVersion = "25.11";
home.packages = with pkgs; [
ripgrep
bat
fzf
];
programs.git = {
enable = true;
userName = "My Name";
userEmail = "me@example.com";
};
};
};
};
}
System Flake (for inventory.nix)
Use this template for host-specific system services (Docker, databases, web servers), hardware configuration tweaks, or system-wide packages.
{
description = "My System Configuration Override";
# No inputs needed! We use the system's packages.
outputs = { self }: {
# This output is what nixos-systems looks for
nixosModules.default = { pkgs, lib, ... }: {
environment.systemPackages = [ pkgs.docker ];
virtualisation.docker.enable = true;
# Example: Override hardware settings defined in the main repo
ugaif.host.filesystem.swapSize = lib.mkForce "64G";
# Example: Enable specific users
ugaif.users.enabledUsers = [ "myuser" ];
# Example: Add a custom binary cache
nix.settings.substituters = [ "https://nix-community.cachix.org" ];
nix.settings.trusted-public-keys = [ "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" ];
};
};
}
Development
Python Environment
All systems include pixi and uv for Python project management. Use these tools for project-specific environments instead of installing global Python packages (which can cause conflicts).
Creating a new project with Pixi:
pixi init my_project
cd my_project
pixi add pandas numpy matplotlib
pixi run python script.py
Using uv for quick tasks:
uv venv
source .venv/bin/activate
uv pip install requests
Testing Changes Locally
Before pushing changes, verify your configuration builds correctly:
# Check all configurations
nix flake check
# Build a specific configuration
nix build .#nixosConfigurations.nix-laptop1.config.system.build.toplevel
# Test an ISO build
nix build .#installer-iso-nix-laptop1
Common Configuration Patterns
Adding System Packages to All Hosts
Edit sw/desktop/programs.nix (or the appropriate type directory) to add packages to the base system:
basePackages = with pkgs; [
htop
vim
git
# Add your packages here
];
Changing Default User Shell
Edit users.nix to set a different shell for a specific user:
myuser = {
description = "My User";
shell = pkgs.fish; # or pkgs.zsh, pkgs.bash
# ... other settings
};
Then ensure the program is enabled in the system configuration (usually already done for common shells).
Troubleshooting
Flake Check Errors
If nix flake check fails, use --show-trace for detailed error information:
nix flake check --show-trace
External Flakes Not Loading
If using flakeUrl, ensure:
- The flake repository is public or you have SSH access configured
- The flake has a
nixosModules.defaultoutput - You're using
--impureflag if the flake has impure operations
Build Failures on Surface Tablets
Surface tablets automatically offload builds to remote builders. If builds fail:
- Verify the remote builder is accessible:
ssh engr-ugaif@nix-builder - Check remote builder has sufficient disk space:
df -h - Try building locally with remote builds disabled by commenting out
ugaif.sw.remoteBuild.enable