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.
This commit is contained in:
Geir Okkenhaug Jerstad 2025-06-04 16:10:13 +02:00
commit f30013723e
43 changed files with 4220 additions and 0 deletions

101
users/README.md Normal file
View file

@ -0,0 +1,101 @@
# Users Directory Structure
This directory contains per-user configurations and dotfiles for the Home-lab infrastructure, organized to support multiple users across multiple machines.
## Directory Organization
### `geir/`
Primary user configuration for geir:
- `user.nix` - NixOS user configuration (packages, groups, shell)
- `dotfiles/` - Literate programming dotfiles using org-mode
- `README.org` - Main literate configuration file
- `emacs/` - Emacs-specific configurations
- `shell/` - Shell configurations (zsh, bash, etc.)
- `editors/` - Editor configurations (neovim, vscode)
### Future Users
Additional user directories will follow the same pattern:
- `admin/` - Administrative user for system management
- `service/` - Service accounts for automation
- `guest/` - Temporary/guest user configurations
## User Configuration Philosophy
### NixOS Integration
Each user has a `user.nix` file that defines:
- User account settings (shell, groups, home directory)
- User-specific packages
- System-level user configurations
- Integration with home lab services
### Literate Dotfiles
Each user's `dotfiles/README.org` serves as:
- Single source of truth for all user configurations
- Self-documenting setup with rationale
- Auto-tangling to generate actual dotfiles
- Version-controlled configuration history
### Multi-Machine Consistency
User configurations are designed to work across machines:
- congenital-optimist: Full development environment
- sleeper-service: Minimal server access
- Future machines: Consistent user experience
## Dotfiles Structure
### `dotfiles/README.org`
Main literate configuration file containing:
- Shell configuration (zsh, starship, aliases)
- Editor configurations (emacs, neovim)
- Development tool settings
- Git configuration
- Machine-specific customizations
### Subdirectories
- `emacs/` - Generated Emacs configuration files
- `shell/` - Generated shell configuration files
- `editors/` - Generated editor configuration files
## Usage Examples
### Importing User Configuration
```nix
# In machine configuration
imports = [
../../users/geir/user.nix
];
```
### Adding New User
1. Create user directory: `users/newuser/`
2. Copy and adapt `user.nix` template
3. Create `dotfiles/README.org` with user-specific configs
4. Import in machine configurations as needed
### Tangling Dotfiles
```bash
# From user's dotfiles directory
cd users/geir/dotfiles
emacs --batch -l org --eval "(org-babel-tangle-file \"README.org\")"
```
## Design Principles
- **User Isolation**: Each user's configs are self-contained
- **Machine Agnostic**: Configs work across different machines
- **Literate Programming**: All configs are documented and explained
- **Version Control**: Full history of configuration changes
- **Automation**: Auto-tangling and deployment workflows
## Security Considerations
- User-specific secrets managed separately
- Limited cross-user access
- Machine-appropriate privilege levels
- Service account isolation
## Naming Convention
- **User Directories**: lowercase (e.g., `geir/`, `admin/`)
- **Configuration Files**: descriptive names (e.g., `user.nix`, `README.org`)
- **Generated Files**: follow target application conventions

View file

@ -0,0 +1,267 @@
#+TITLE: Userland configurations for Geir Okkenhaug Jerstad
#+AUTHOR: Geir Okkenhaug Jerstad
#+DATE: [2025-05-28]
#+STARTUP: overview
#+PROPERTY: header-args :tangle yes
#+PROPERTY: header-args:nix :mkdirp yes
* Introduction
Socalled dotfiles, or userland configurations, are personal configurations for various tools
and applications.
* Sway
Configuration for sway waybar fuzzel and other sway related tools
#+BEGIN_SRC shell :tangle /home/geir/.config/sway/config
default_border none
### Variables
#
# Logo key. Use Mod1 for Alt.
set $mod Mod4
# Home row direction keys, like vim
set $left h
set $down j
set $up k
set $right l
# Your preferred terminal emulator
set $term kitty
set $menu fuzzel
# Set gnome stuff
set $gnome-schema org.gnome.desktop.interface
### Output configuration
#
# Default wallpaper (more resolutions are available in /run/current-system/sw/share/backgrounds/sway/)
output * bg /home/geir/Pictures/wall.jpg fill
#
# Example configuration:
#
# output HDMI-A-1 resolution 1920x1080 position 1920,0
#
# You can get the names of your outputs by running: swaymsg -t get_outputs
### Idle configuration
#
# Example configuration:
#
exec swayidle -w \
timeout 1200 'swaylock -f -c 000000' \
timeout 36000 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' \
before-sleep 'swaylock -f -c 000000'
# This will lock your screen after 600 seconds of inactivity, then turn off
# your displays after another 600 seconds, and turn your screens back on when
# resumed. It will also lock your screen before your computer goes to sleep.
### Input configuration
#
# Example configuration:
#
input "type:touchpad" {
dwt enabled
tap enabled
natural_scroll enabled
middle_emulation enabled
}
#
# You can get the names of your inputs by running: swaymsg -t get_inputs
# Read `man 5 sway-input` for more information about
# or input <identifier>
input "type:keyboard" {
xkb_layout "us, no"
xkb_variant ,nodeadkeys
xkb_options "caps:ctrl_modifier, grp:win_space_toggle"
}
# screenshots
bindsym $mod+c exec flameshot gui -p /home/geir/Pictures/Screenshots
### Key bindings
#
# Basics:
#
# Start a terminal
bindsym $mod+Return exec $term
# Kill focused window
bindsym $mod+Shift+q kill
# Start your launcher
bindsym $mod+d exec $menu
# Drag floating windows by holding down $mod and left mouse button.
floating_modifier $mod normal
# Reload the configuration file
bindsym $mod+Shift+c reload
# Exit sway (logs you out of your Wayland session)
bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -B 'Yes, exit sway' 'swaymsg exit'
#
# Moving around:
#
# Move your focus around
bindsym $mod+$left focus left
bindsym $mod+$down focus down
bindsym $mod+$up focus up
bindsym $mod+$right focus right
# Or use $mod+[up|down|left|right]
bindsym $mod+Left focus left
bindsym $mod+Down focus down
bindsym $mod+Up focus up
bindsym $mod+Right focus right
# Move the focused window with the same, but add Shift
bindsym $mod+Shift+$left move left
bindsym $mod+Shift+$down move down
bindsym $mod+Shift+$up move up
bindsym $mod+Shift+$right move right
# Ditto, with arrow keys
bindsym $mod+Shift+Left move left
bindsym $mod+Shift+Down move down
bindsym $mod+Shift+Up move up
bindsym $mod+Shift+Right move right
#
# Workspaces:
#
# Switch to workspace
bindsym $mod+1 workspace number 1
bindsym $mod+2 workspace number 2
bindsym $mod+3 workspace number 3
bindsym $mod+4 workspace number 4
bindsym $mod+5 workspace number 5
bindsym $mod+6 workspace number 6
bindsym $mod+7 workspace number 7
bindsym $mod+8 workspace number 8
bindsym $mod+9 workspace number 9
bindsym $mod+0 workspace number 10
# Move focused container to workspace
bindsym $mod+Shift+1 move container to workspace number 1
bindsym $mod+Shift+2 move container to workspace number 2
bindsym $mod+Shift+3 move container to workspace number 3
bindsym $mod+Shift+4 move container to workspace number 4
bindsym $mod+Shift+5 move container to workspace number 5
bindsym $mod+Shift+6 move container to workspace number 6
bindsym $mod+Shift+7 move container to workspace number 7
bindsym $mod+Shift+8 move container to workspace number 8
bindsym $mod+Shift+9 move container to workspace number 9
bindsym $mod+Shift+0 move container to workspace number 10
#
# Layout stuff:
#
# You can "split" the current object of your focus with
# $mod+b or $mod+v, for horizontal and vertical splits
# respectively.
bindsym $mod+b splith
bindsym $mod+v splitv
# Switch the current container between different layout styles
bindsym $mod+s layout stacking
bindsym $mod+w layout tabbed
bindsym $mod+e layout toggle split
# Make the current focus fullscreen
bindsym $mod+f fullscreen
# Toggle the current focus between tiling and floating mode
bindsym $mod+Shift+space floating toggle
# Swap focus between the tiling area and the floating area
bindsym $mod+ctrl+space focus mode_toggle
# Move focus to the parent container
bindsym $mod+a focus parent
#
# Scratchpad:
#
# Sway has a "scratchpad", which is a bag of holding for windows.
# You can send windows there and get them back later.
# Move the currently focused window to the scratchpad
bindsym $mod+Shift+minus move scratchpad
# Show the next scratchpad window or hide the focused scratchpad window.
# If there are multiple scratchpad windows, this command cycles through them.
bindsym $mod+minus scratchpad show
#
# Resizing containers:
#
mode "resize" {
# left will shrink the containers width
# right will grow the containers width
# up will shrink the containers height
# down will grow the containers height
bindsym $left resize shrink width 10px
bindsym $down resize grow height 10px
bindsym $up resize shrink height 10px
bindsym $right resize grow width 10px
# Ditto, with arrow keys
bindsym Left resize shrink width 10px
bindsym Down resize grow height 10px
bindsym Up resize shrink height 10px
bindsym Right resize grow width 10px
# Return to default mode
bindsym Return mode "default"
bindsym Escape mode "default"
}
bindsym $mod+r mode "resize"
#
# Status Bar:
#
bar {
swaybar_command waybar
}
include /etc/sway/config.d/*
exec dbus-sway-environment
exec configure-gtk
exec gammastep
*+END_SRC
* Zsh
Configuration for zsh.
#+BEGIN_SRC shell :tangle /home/geir/.config/zsh/.zshrc
# Zsh configuration for Geir Okkenhaug Jerstad
zstyle ':completion:*' completer _expand _complete _ignored
zstyle ':completion:*' matcher-list ''
zstyle :compinstall filename '/home/geir/.zshrc'
autoload -Uz compinit
compinit
HISTFILE=~/.histfile
HISTSIZE=10000
SAVEHIST=10000
setopt autocd extendedglob
unsetopt beep nomatch
bindkey -e
eval "$(starship init zsh)"
eval "$(direnv hook zsh)"
eval "$(zoxide init zsh)"
fortune -s | cowsay -f dragon | clolcat
#+END_SRC
* Git
Configuration for git.
#+BEGIN_SRC shell :tangle /home/geir/.gitconfig
user.email=geokkjer@gmail.com
user.name=Geir Okkenhaug Jerstad
filter.lfs.smudge=git-lfs smudge -- %f
filter.lfs.process=git-lfs filter-process
filter.lfs.required=true
filter.lfs.clean=git-lfs clean -- %f
init.defaultbranch=main
#+END_SRC

View file

@ -0,0 +1,222 @@
#+title: Emacs Configuration
#+author: Geir Okkenhaug Jerstad
#+email: geir@geokkjer.eu
#+options: toc:nil num:nil
#+PROPERTY: header-args:emacs-lisp :tangle ~/.emacs.d/init.el
* About
My attempt at a litterate configuration for Emacs.
to tangle this file.
keyboard shortcut `C-c C-v t` (org-babel-tangle) in Emacs.
This will generate the `~/.emacs.d/init.el` file with the configuration.
* Prep
* Configuration
** Setup lexical binding
Here we set up lexical binding, which is a feature in Emacs Lisp that allows for more efficient variable scoping and function closures. This is recommended for performance reasons.
#+BEGIN_SRC emacs-lisp
;; enable lexical binding
(setq lexical-binding t)
#+END_SRC
** Set automatic update of packages
We set up Emacs to automatically update packages on startup. This ensures that we always have the latest versions of the packages we use.
#+BEGIN_SRC emacs-lisp
(defun geokkjer/display-startup-time ()
(message "Emacs loaded in %s with %d grabage collections."
(format "%.2f seconds"
(float-time
(time-subtract after-init-time before-init-time)))
gcs-done))
(add-hook 'emacs-startup-hook #'geokkjer/display-startup-time)
(setq gc-cons-threshold (* 50 1000 1000))
#+END_SRC
** Customize UI
Here we set up the UI to our liking. We disable the menu bar, tool bar, and scroll bar, and set the font size to 14pt.
#+BEGIN_SRC emacs-lisp
;; disable startup screen
(setq inhibit-startup-screen t)
;; disable menu bar
(menu-bar-mode -1)
;; disable tool bar
(tool-bar-mode -1)
;; disable scroll bar
(scroll-bar-mode -1)
;; set font size
(set-face-attribute 'default nil :height 140)
#+END_SRC
Set up package management
#+BEGIN_SRC
;; Initialize package sources
(require 'package)
;; Set the repos
(setq package-archives '(("melpa" . "https://melpa.org/packages/")
("org" . "https://orgmode.org/elpa/")
("nongnu" . "https://elpa.nongnu.org/nongnu/")
("elpa" . "https://elpa.gnu.org/packages/")))
(package-initialize)
(unless package-archive-contents
(package-refresh-contents))
#+END_SRC
Set up doom modeline, which is a nice status line for Emacs. We set it up to show the current buffer name and the current line number.
#+BEGIN_SRC emacs-lisp
;; Doom modline, all-the-icons and doom-theme
(use-package doom-modeline
:ensure t
:init (doom-modeline-mode 1)
:custom ((doom-modeline-height 15)))
(setq doom-modeline-icon t)
(use-package all-the-icons)
(use-package doom-themes
:init (load-theme 'doom-monokai-pro t))
#+END_SRC
Set up all-the-icons, which provides icons for various file types and modes in Emacs. This enhances the visual appearance of the UI.
install all-the-icons if not already installed with '<M-x> all-the-icons-install-fonts'
#+BEGIN_SRC emacs-lisp
(use-package all-the-icons
:if (display-graphic-p) ;; only load in GUI Emacs
:ensure t
:init
(unless (package-installed-p 'all-the-icons)
(package-refresh-contents)
(package-install 'all-the-icons))
:config
(all-the-icons-setup))
#+END_SRC
** Org Mode
Configure Org-mode for literate programming and note-taking.
#+BEGIN_SRC emacs-lisp
;; ensure org-mode is installed and up to date
(use-package org
:ensure t
:mode ("\\.org\\'" . org-mode)
:config
;; enable syntax highlighting in code blocks
(setq org-src-fontify-natively t)
;; preserve indentation in code blocks
(setq org-src-preserve-indentation t)
;; enable babel for code execution
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(shell . t)
(python . t)
(nix . t)))
;; don't ask for confirmation when evaluating code blocks
(setq org-confirm-babel-evaluate nil))
#+END_SRC
* Code Completion and ide features
** LSP Mode
Here we install lsp-mode and lsp-ui, which are the core components of the LSP (Language Server Protocol) support in Emacs. We also set up keybindings for common LSP commands.
#+BEGIN_SRC emacs-lisp
;; install lsp-mode and lsp-ui if not already installed
(unless (package-installed-p 'lsp-mode)
(package-refresh-contents)
(package-install 'lsp-mode))
(unless (package-installed-p 'lsp-ui)
(package-refresh-contents)
(package-install 'lsp-ui))
(require 'lsp-mode)
(require 'lsp-ui)
;; enable lsp-mode in programming buffers
(add-hook 'prog-mode-hook #'lsp)
;; Enable line numbers
(column-number-mode)
(global-display-line-numbers-mode t)
#+END_SRC
** GitHub Copilot
Here we install from MELPA, enable it in all prog-modes and bind keys for completion:
run <M-x> copilot-install-server and <M-x> copilot-login
#+BEGIN_SRC emacs-lisp
;; ensure Copilot is installed
(unless (package-installed-p 'copilot)
(package-refresh-contents)
(package-install 'copilot))
(require 'copilot)
;; turn on in programming buffers
(add-hook 'prog-mode-hook #'copilot-mode)
;; keybindings: M-TAB to trigger, TAB to accept
(define-key copilot-mode-map (kbd "M-TAB") #'copilot-complete)
(define-key copilot-completion-map (kbd "<tab>") #'copilot-accept-completion)
#+END_SRC
Copilot Chat
#+BEGIN_SRC emacs-lisp
(unless (package-installed-p 'copilot-chat)
(package-install 'copilot-chat))
(use-package copilot-chat
:bind (:map global-map
("C-c C-y" . copilot-chat-yank)
("C-c M-y" . copilot-chat-yank-pop)
("C-c C-M-y" . (lambda () (interactive) (copilot-chat-yank-pop -1))))
)
#+END_SRC
** Language support
Here we install and configure support for various programming languages. We use the `use-package` macro to ensure that the packages are installed and configured correctly.
** NixOS from Emacs
Editing Nix files and doing NixOS admin stuff like nixos-rebuild boot --upgrade
Run the commands with M-x shell-command
#+BEGIN_SRC emacs-lisp
;; NixOS commands
(defun nixos-upgrade ()
"Run 'nixos-rebuild boot --upgrade' in a shell."
(interactive)
(shell-command "nixos-rebuild boot --upgrade"))
(defun nixos-switch ()
"Run 'nixos-rebuild switch' in a shell."
(interactive)
(shell-command "nixos-rebuild switch"))
#+END_SRC
#+BEGIN_SRC emacs-lisp
;; install nix-mode
(use-package nix-mode
:ensure t
:mode "\\.nix\\'")
;; install nix-repl
(use-package nix-repl
:ensure t
:mode "\\.nix\\'")
;; install nixpkgs
(use-package nixpkgs
:ensure t
:mode "\\.nix\\'")
#+END_SRC

69
users/geir/user.nix Normal file
View file

@ -0,0 +1,69 @@
{ pkgs, ... }:
{
users.users.geir = {
isNormalUser = true;
extraGroups = [ "networkmanager" "wheel" ];
shell = pkgs.zsh;
packages = with pkgs; [
# Browsers
chromium
vivaldi
vivaldi-ffmpeg-codecs
nyxt
firefox
# Shell & tools
zsh
zsh-completions
nix-zsh-completions
starship
nix-direnv
# Audio & system
ncpamixer
fastfetch
hyfetch
nerdfetch
emacsPackages.vterm
virt-manager
pavucontrol
gnome-tweaks
beauty-line-icon-theme
# Fun & misc
neo-cowsay
fortune
clolcat
zellij
gimp
vesktop
koodo-reader
# Github CLI
gh
];
};
environment.systemPackages = with pkgs;
[
zsh
zsh-completions
nix-zsh-completions
zsh-autocomplete
zsh-autosuggestions
zsh-syntax-highlighting
];
programs.zsh.enable = true;
programs.zsh.syntaxHighlighting.enable = true;
programs.zsh.enableCompletion = true;
programs.zsh.autosuggestions = {
enable = true;
historySearch = true;
};
programs.zsh.history = {
enable = true;
shareHistory = true;
saveOnExit = true;
};
}