home-lab/instruction.md
Geir Okkenhaug Jerstad f30013723e feat: initial NixOS home lab infrastructure setup
- Add modular flake-based NixOS configuration
- Implement GitOps foundation with CI/CD pipeline
- Create comprehensive documentation and branching strategy
- Add modular desktop environments (GNOME, Cosmic, Sway)
- Configure virtualization stack (Incus, Libvirt, Podman)
- Set up development tools and hardware-specific modules
- Establish user configuration with literate programming support

This commit represents the completion of Phase 1: Flakes Migration
with modular configuration, virtualization, and GitOps foundation.
2025-06-04 16:10:13 +02:00

19 KiB

AI Agent Instructions: NixOS Flakes Migration for CongenitalOptimist

Overview

This document provides step-by-step instructions for AI agents to help migrate the CongenitalOptimist machine from traditional NixOS configuration to flakes-based configuration and upgrade to NixOS 25.05. The system already has excellent modular structure that we'll preserve and enhance.

Current System Information

  • Hostname: work (consider renaming to congenital-optimist)
  • Current Version: NixOS 23.11
  • Target Version: NixOS 25.05
  • Architecture: x86_64-linux
  • Storage: ZFS (zpool for system, stuffpool for data)
  • Hardware: AMD CPU/GPU
  • User: geir
  • Dotfiles Approach: Literate programming with Emacs org-mode (no Home Manager)

Current Module Structure

Home-lab/
├── machines/
│   ├── congenital-optimist/
│   │   ├── configuration.nix (main system config)
│   │   ├── hardware-configuration.nix
│   │   └── About.org
│   └── modules/
│       ├── common/
│       │   ├── base.nix (modern CLI tools & aliases)
│       │   └── tty.nix (console styling with Joker theme)
│       └── virtualization/
│           ├── podman.nix
│           ├── libvirt.nix
│           └── incus.nix
└── Users/
    └── geir/
        └── user.nix (has typo: progtams → programs)

Prerequisites Check

Before starting, verify:

  1. Current system is bootable and stable
  2. ZFS pools are healthy (zpool status)
  3. All referenced modules exist and are working
  4. User has sudo/root access
  5. Fix typo in Users/geir/user.nix first

Step 1: Fix Existing Configuration Issues

Fix typo in user.nix

Edit Home-lab/Users/geir/user.nix and change:

progtams.zsh.enableCompletion = true;

to:

programs.zsh.enableCompletion = true;

Step 2: Create Root Flake Structure

Create Home-lab/flake.nix:

{
  description = "CongenitalOptimist Home Lab NixOS Configuration";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
    nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
  };

  outputs = { self, nixpkgs, nixpkgs-unstable, ... }@inputs: {
    nixosConfigurations = {
      congenital-optimist = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        specialArgs = { 
          inherit inputs;
          unstable = import nixpkgs-unstable { 
            system = "x86_64-linux"; 
            config.allowUnfree = true; 
          };
        };
        modules = [
          ./machines/congenital-optimist
        ];
      };
    };
  };
}

Step 3: Create Target Directory Structure

Execute these commands in the Home-lab directory:

mkdir -p machines/congenital-optimist
mkdir -p modules/{common,desktop,development,virtualization,users}
mkdir -p users/geir/dotfiles/{emacs,shell,editors}
mkdir -p overlays
mkdir -p packages

Step 4: Convert Main Configuration

Create machines/CongenitalOptimist/default.nix by adapting the current configuration.nix:

Key changes needed:

  1. Change function signature from {pkgs, ...}: to { config, pkgs, inputs, unstable, ... }:
  2. Keep system.stateVersion as "23.11" (maintains compatibility with existing data)
  3. Fix nerd-fonts syntax (changed in 25.05)
  4. Remove the experimental-features setting (handled by flake)
  5. Update module import paths for new structure
  6. Consolidate user package management

Nerd Fonts Fix for 25.05

Replace this section in fonts.packages:

# Old format (will break in 25.05)
nerd-fonts.meslo-lg
nerd-fonts.jetbrains-mono
nerd-fonts.fira-code
nerd-fonts.droid-sans-mono
nerd-fonts.zed-mono
nerd-fonts.iosevka
nerd-fonts.iosevka-term
nerd-fonts.hack

With:

# New format for 25.05
(nerdfonts.override { 
  fonts = [ 
    "Meslo" 
    "JetBrainsMono" 
    "FiraCode" 
    "DroidSansMono" 
    "Hack" 
    "Iosevka" 
    "IosevkaTerm" 
  ]; 
})

Step 5: Migrate Existing Modules

Copy existing modules to new structure:

# Copy common modules
cp Home-lab/Machines/Modules/common/base.nix modules/common/
cp Home-lab/Machines/Modules/common/tty.nix modules/common/

# Copy virtualization modules
cp Home-lab/Machines/Modules/virtualization/*.nix modules/virtualization/

Create additional common modules:

modules/common/nix.nix:

{ config, pkgs, ... }: {
  # Enable flakes system-wide
  nix.settings.experimental-features = [ "nix-command" "flakes" ];
  
  # Optimize nix settings
  nix.settings = {
    auto-optimise-store = true;
    substituters = [
      "https://cache.nixos.org/"
    ];
    trusted-public-keys = [
      "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
    ];
  };
}

Step 6: Consolidate User Configuration

Create modules/users/geir.nix by merging the existing user config:

{ config, pkgs, ... }: {
  users.users.geir = {
    isNormalUser = true;
    extraGroups = [ "networkmanager" "wheel" "libvirtd" "podman" "incus-admin" ];
    shell = pkgs.zsh;
    packages = with pkgs; [
      # Browsers
      chromium
      vivaldi
      vivaldi-ffmpeg-codecs
      nyxt
      firefox

      # Shell & development tools
      starship
      fastfetch
      hyfetch
      nerdfetch
      nix-direnv
      gh
      github-copilot-cli

      # Media & graphics
      gimp
      obs-studio
      vesktop
      koodo-reader

      # System tools
      ncpamixer
      virt-manager
      pavucontrol
      gnome-tweaks
      beauty-line-icon-theme
      
      # Terminal multiplexer and fun
      zellij
      neo-cowsay
      fortune
      clolcat
      
      # Emacs integration
      emacsPackages.vterm
    ];
  };

  # System-wide ZSH configuration
  programs.zsh = {
    enable = true;
    syntaxHighlighting.enable = true;
    enableCompletion = true;
    autosuggestions = {
      enable = true;
      historySearch = true;
    };
    history = {
      enable = true;
      shareHistory = true;
      saveOnExit = true;
    };
  };

  environment.systemPackages = with pkgs; [
    zsh
    zsh-completions
    nix-zsh-completions
    zsh-autocomplete
    zsh-autosuggestions
    zsh-syntax-highlighting
  ];
}

Step 7: Create Desktop Environment Modules

modules/desktop/gnome.nix:

{ config, pkgs, ... }: {
  services.xserver = {
    enable = true;
    desktopManager.gnome.enable = true;
    xkb.layout = "no";
  };
  
  # XDG portal configuration
  xdg.portal = {
    enable = true;
    extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
  };
}

modules/desktop/cosmic.nix:

{ config, pkgs, ... }: {
  services.desktopManager.cosmic.enable = true;
  services.displayManager.cosmic-greeter.enable = true;
  services.desktopManager.cosmic.xwayland.enable = true;
}

modules/desktop/sway.nix:

{ config, pkgs, ... }: {
  programs.sway = {
    enable = true;
    wrapperFeatures.gtk = true;
  };
  
  services.dbus.enable = true;
  
  xdg.portal = {
    enable = true;
    wlr.enable = true;
    extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
  };

  environment.systemPackages = with pkgs; [
    swaylock
    swayidle
    swaybg
    waybar
    fuzzel
    gammastep
    mako
    flameshot
  ];
}

Step 8: Set Up Per-User Literate Dotfiles

Create users/geir/dotfiles/README.org:

#+TITLE: CongenitalOptimist Dotfiles Configuration
#+DESCRIPTION: Literate programming approach to dotfiles using Emacs org-mode
#+PROPERTY: header-args :tangle yes
#+STARTUP: overview

* Introduction
This file contains all dotfiles configuration using literate programming.
Each configuration block can be tangled to its respective file using C-c C-v t.

The approach allows for:
- Self-documenting configuration with rationale
- Easy sharing and explanation of setup decisions
- Version control of configuration with full context
- Modular organization of different tool configurations

* Shell Configuration
** Zsh Configuration
#+BEGIN_SRC sh :tangle ~/.zshrc
# Generated from dotfiles/README.org - CongenitalOptimist configuration
export EDITOR="emacs"
export BROWSER="firefox"
export SHELL="/run/current-system/sw/bin/zsh"

# Enable starship prompt (configured in NixOS)
eval "$(starship init zsh)"

# Enable zoxide for smart cd
eval "$(zoxide init zsh)"

# Custom aliases (complementing those in base.nix)
alias gc='git commit'
alias gp='git push'
alias gs='git status'
alias nrs='sudo nixos-rebuild switch --flake .'
alias nrt='sudo nixos-rebuild test --flake .'
alias reload='source ~/.zshrc'

# CongenitalOptimist specific shortcuts
alias lab='cd ~/Home-lab'
alias tangle='cd ~/Home-lab/users/geir/dotfiles && emacs --batch -l org --eval "(org-babel-tangle-file \"README.org\")"'
alias dotfiles='cd ~/Home-lab/users/geir/dotfiles'
#+END_SRC

** Starship Configuration  
#+BEGIN_SRC toml :tangle ~/.config/starship.toml
# Starship prompt configuration for CongenitalOptimist
format = """
$username\
$hostname\
$directory\
$git_branch\
$git_state\
$git_status\
$cmd_duration\
$line_break\
$character"""

[character]
success_symbol = "[➜](bold green)"
error_symbol = "[➜](bold red)"

[directory]
truncation_length = 3
fish_style_pwd_dir_length = 1

[git_branch]
symbol = "🌱 "

[hostname]
ssh_only = false
format = "[@$hostname](bold blue) "

[username]
show_always = true
format = "[$user](bold yellow)"
#+END_SRC

* Editor Configuration
** Emacs Configuration
#+BEGIN_SRC emacs-lisp :tangle ~/.emacs.d/init.el
;; Generated from dotfiles/README.org - CongenitalOptimist
(setq inhibit-startup-message t)
(setq ring-bell-function 'ignore)

;; Enable line numbers
(global-display-line-numbers-mode 1)

;; Enable org-babel for literate programming
(org-babel-do-load-languages
 'org-babel-load-languages
 '((emacs-lisp . t)
   (shell . t)
   (python . t)
   (nix . t)))

;; Auto-tangle on save for literate config files
(defun auto-tangle-config-files ()
  "Auto tangle config files when saving."
  (when (string-match-p "users/.*/dotfiles.*\\.org$" (buffer-file-name))
    (org-babel-tangle)))

(add-hook 'after-save-hook 'auto-tangle-config-files)

;; Better defaults
(setq-default indent-tabs-mode nil)
(setq-default tab-width 2)
(show-paren-mode 1)
(electric-pair-mode 1)

;; CongenitalOptimist theme setup
(when (display-graphic-p)
  (load-theme 'deeper-blue t))
#+END_SRC

* Development Tools
** Git Configuration
#+BEGIN_SRC conf :tangle ~/.gitconfig
[user]
    name = geir
    email = geir@congenital-optimist.local

[init]
    defaultBranch = main

[core]
    editor = emacs
    pager = bat

[pull]
    rebase = false

[alias]
    st = status
    co = checkout
    br = branch
    unstage = reset HEAD --
    last = log -1 HEAD
    visual = !gitk
#+END_SRC

* Home Lab Specific Configuration
** NixOS Rebuild Aliases
These aliases make working with the flake-based configuration easier:

#+BEGIN_SRC sh :tangle ~/.config/shell/nixos-aliases
# NixOS CongenitalOptimist specific aliases
alias nix-build='cd ~/Home-lab && nix build .#nixosConfigurations.congenital-optimist.config.system.build.toplevel'
alias nix-check='cd ~/Home-lab && nix flake check'
alias nix-update='cd ~/Home-lab && nix flake update'
alias nix-clean='sudo nix-collect-garbage -d'
alias edit-dotfiles='cd ~/Home-lab/users/geir/dotfiles && emacs README.org'
#+END_SRC

Step 9: Update Main Configuration Import Structure

Create the main machine configuration in machines/CongenitalOptimist/default.nix:

{ config, pkgs, inputs, unstable, ... }: {
  imports = [
    ./hardware-configuration.nix
    ../../modules/common/base.nix
    ../../modules/common/tty.nix
    ../../modules/common/nix.nix
    ../../modules/virtualization/podman.nix
    ../../modules/virtualization/libvirt.nix
    ../../modules/virtualization/incus.nix
    ../../modules/desktop/gnome.nix
    ../../modules/desktop/cosmic.nix
    ../../modules/desktop/sway.nix
    ../../modules/users/geir.nix
  ];

  # Boot configuration
  boot.loader.grub = {
    enable = true;
    zfsSupport = true;
    efiSupport = true;
    efiInstallAsRemovable = true;
    mirroredBoots = [
      {
        devices = ["nodev"];
        path = "/boot";
      }
    ];
  };
  
  zramSwap = {
    enable = true;
    algorithm = "zstd";
  };

  # Hardware
  services.fwupd.enable = true;
  hardware.enableRedistributableFirmware = true;
  hardware.amdgpu.initrd.enable = true;
  hardware.bluetooth.enable = true;
  hardware.bluetooth.powerOnBoot = true;

  # System settings
  nixpkgs.config.allowUnfree = true;
  networking.nftables.enable = true;
  networking.hostName = "work"; # TODO: consider changing to "congenital-optimist"
  services.tailscale.enable = true;
  networking.networkmanager.enable = true;
  networking.hostId = "8425e349";
  time.timeZone = "Europe/Oslo";
  i18n.defaultLocale = "en_US.UTF-8";

  # Services
  services.flatpak.enable = true;
  services.emacs.enable = true;
  services.pipewire = {
    enable = true;
    alsa.enable = true;
    pulse.enable = true;
  };
  programs.steam.enable = true;

  # Fonts (updated for 25.05)
  fonts.packages = with pkgs; [
    noto-fonts
    noto-fonts-cjk-sans
    noto-fonts-emoji
    liberation_ttf
    dina-font
    proggyfonts
    mona-sans
    hubot-sans
    inter-nerdfont
    (nerdfonts.override { 
      fonts = [ 
        "Meslo" 
        "JetBrainsMono" 
        "FiraCode" 
        "DroidSansMono" 
        "Hack" 
        "Iosevka" 
        "IosevkaTerm" 
      ]; 
    })
  ];

  # System packages
  environment.systemPackages = with pkgs; [
    # Terminal applications
    kitty
    terminator
    rio
    dbus
    greetd.tuigreet
    wayland
    xdg-utils

    # System monitoring
    glances
    inxi
    htop
    bottom
    wget
    curl
    git
    mc
    systemctl-tui

    # Development tools
    guile
    rustup
    nixd
    zls
    alejandra
    python3Packages.python-lsp-server
    gopls
    luajitPackages.lua-lsp
    nodePackages.bash-language-server
    vimPlugins.cmp-nvim-lsp
    ccls
    gdb
    marksman

    # Editors
    zed-editor
    neovim
    emacs
    vscode
    vscodium-fhs
  ];

  # Network and security
  services.openssh.enable = true;
  services.zfs.autoScrub.enable = true;
  services.zfs.trim.enable = true;
  networking.firewall.allowedTCPPorts = [ 22 ];
  networking.firewall.allowedUDPPorts = [ 22 ];
  networking.firewall.enable = true;

  system.copySystemConfiguration = true;
  system.stateVersion = "23.11"; # DO NOT CHANGE - maintains data compatibility
}

Step 10: Copy Hardware Configuration

Copy the existing hardware configuration:

cp Home-lab/Machines/CongenitalOptimist/hardware-configuration.nix machines/CongenitalOptimist/

Step 11: Test Configuration

Before applying changes:

  1. Test flake evaluation:
cd Home-lab
nix flake check
  1. Build configuration without switching:
sudo nixos-rebuild build --flake .#congenital-optimist
  1. If successful, test the configuration:
sudo nixos-rebuild test --flake .#congenital-optimist
  1. If everything works, switch permanently:
sudo nixos-rebuild switch --flake .#congenital-optimist

Step 12: Set Up Per-User Literate Dotfiles Workflow

  1. Create your main org-mode configuration file:
cd users/geir/dotfiles
emacs README.org
  1. Use org-babel to tangle your configurations:
# In Emacs, use C-c C-v t to tangle all code blocks
# Or from command line:
cd users/geir/dotfiles
emacs --batch -l org --eval "(org-babel-tangle-file \"README.org\")"
  1. The provided Emacs config includes auto-tangle on save for any user's dotfiles
  2. Test that dotfiles are generated correctly in the user's home directory
  3. For additional users, create similar structure under users/<username>/dotfiles/

Step 13: Lock and Commit

  1. Generate flake.lock:
nix flake lock
  1. Commit changes:
git add .
git commit -m "Migrate CongenitalOptimist to flakes with literate dotfiles"

Verification Steps

After switching:

  1. Verify system boots correctly
  2. Check all services are running: systemctl --failed
  3. Test all desktop environments launch (GNOME, Cosmic, Sway)
  4. Verify virtualization: sudo systemctl status libvirtd podman
  5. Check ZFS status: zpool status
  6. Test network connectivity and Tailscale
  7. Verify user environment and all packages available
  8. Test modern CLI tools and aliases from base.nix
  9. Check console theming and TTY configuration
  10. Verify Emacs and literate programming workflow

Error Resolution

Common Issues:

  1. Boot failure: Boot from previous generation in GRUB
  2. Package not found: Check if package name changed in 25.05
  3. Service fails: Check journalctl: journalctl -u <service-name>
  4. Desktop environment issues: Switch to TTY (Ctrl+Alt+F2) and debug
  5. Nerd fonts issues: Verify the new syntax is applied correctly

Emergency Recovery:

  • Boot from previous NixOS generation in GRUB
  • Use ZFS snapshots if available: zfs rollback zpool/root@snapshot-name
  • Keep live USB available for emergency repairs

Final Validation Checklist

  • System boots to desktop
  • All user applications launch (browsers, editors, terminals)
  • Network and Tailscale functional
  • Virtualization stack operational (podman, libvirt, incus)
  • ZFS and NFS mounts working
  • Development tools functional (editors, LSPs, languages)
  • Audio system working (pipewire)
  • Modern CLI tools and aliases from base.nix working
  • Console theming with Joker palette preserved
  • Bluetooth functional if needed
  • Literate dotfiles workflow established
  • Auto-tangling in Emacs working

Post-Migration Tasks

  1. Consider updating hostname from "work" to "congenital-optimist"
  2. Expand literate dotfiles in org-mode with more tools and configurations
  3. Create additional machine configurations in the flake
  4. Implement secrets management (agenix/sops-nix)
  5. Set up automatic updates
  6. Add system monitoring
  7. Document your literate programming workflow per user
  8. Consider using org-mode for documenting the entire home lab setup
  9. Set up org-export to generate beautiful documentation from your configs
  10. Create templates for common user configuration patterns
  11. Plan for additional users with their own dotfiles directories
  12. Consider shared vs user-specific configuration strategies

Notes for AI Agents

  1. Always preserve existing functionality - don't remove working features
  2. The system already has excellent modular structure - build on it
  3. Modern CLI tools are already configured in base.nix - don't duplicate
  4. Console theming is already set up - preserve the Joker palette
  5. Fix the typo in user.nix before proceeding
  6. Keep system.stateVersion as "23.11" - never change this
  7. Test thoroughly before committing to permanent changes
  8. Prioritize system stability over new features
  9. The literate programming approach should complement, not replace, the modular NixOS structure