Personal NixOS + Home Manager configuration. A work in progress as I learn the Nix ecosystem.
- Unified config across Linux desktops and servers
- Single user config that adapts to each machine type
- Reproducible, declarative system management
- Learn Nix patterns and best practices along the way
| Machine | Type | Status |
|---|---|---|
acer-swift |
Linux laptop (Hyprland) | Active |
lenovo-21CB001PMX |
Linux laptop (Hyprland) | Active |
msi-ms7758 |
Headless k3s worker node (legacy NVIDIA GPU for Ollama); Windows dual-boot for gaming | Active |
workstation-template |
KubeVirt workstation image | Active |
flake.nix # Minimal flake-parts entrypoint (auto-imports flake modules)
├── flake-modules/ # Top-level flake modules (dendritic trunk)
│ ├── 00-flake-parts-modules.nix
│ ├── 10-systems.nix
│ ├── 20-module-registry.nix
│ ├── 30-configurations-options.nix
│ ├── 40-outputs-nixos.nix
│ └── hosts/ # Distribution declarations
├── hosts/ # Per-machine configs
│ ├── acer-swift/
│ │ ├── configuration.nix
│ │ ├── hardware-configuration.nix
│ │ ├── home.nix
│ │ └── variables.nix
│ ├── lenovo-21CB001PMX/
│ ├── configuration.nix
│ ├── hardware-configuration.nix
│ ├── home.nix
│ └── variables.nix
│ └── msi-ms7758/
│ ├── configuration.nix
│ ├── hardware-configuration.nix
│ ├── home.nix
│ └── variables.nix
├── modules/ # Reusable modules
│ ├── core/ # System baseline (nix, users, services, fonts)
│ ├── desktop/ # Desktop stacks (Hyprland, i3)
│ ├── hardware/ # Hardware drivers
│ ├── programs/ # Home Manager program modules
│ ├── roles/ # Base/desktop/laptop composition
│ └── themes/ # Theme definitions
├── lib/ # Shared helpers (users, theme)
├── assets/ # Wallpapers and other assets
├── dotfiles/ # Plain config files (symlinked)
├── secrets/ # Secrets (handled out-of-band)
└── tmp/ # Local comparison/scratch (gitignored)
Each host lives in hosts/<name>/ and provides:
variables.nix: choices for desktop, theme, apps, hardwareconfiguration.nix: system modules for that hosthome.nix: Home Manager modules for that host
flake.nix now uses flake-parts with flake-parts.flakeModules.modules (the deferredModule registry):
- Every file under
flake-modules/is imported as a top-level flake module flake.modules.nixos.role-*is auto-generated frommodules/roles/*.nixflake.modules.homeManager.host-*is auto-generated fromhosts/*/home.nixconfigurations.nixos.*are typed distribution declarations converted into flake outputs
This establishes a dendritic-style flake trunk for top-level composition: typed, classed module registries with no lower-level specialArgs pass-through.
flake.nix keeps flake.modules internal to evaluation and removes the public modules flake output so nix flake check stays warning-free.
Host distributions are composed from typed options (sam.profile, sam.userConfig) and role aspects from variables.nix, rather than passing host-specific specialArgs into reusable modules.
Roles are driven by variables.nix:
roles = [ "base" "laptop" "desktop" ]for laptops- Drop
"desktop"for headless machines to keep the same shell/CLI baseline without a GUI
# Build and switch (Linux)
sudo nixos-rebuild switch --flake .#acer-swift
sudo nixos-rebuild switch --flake .#lenovo
sudo nixos-rebuild switch --flake .#msi-ms7758
# Test build without applying
sudo nixos-rebuild build --flake .#acer-swift
# Update all inputs
nix flake update
# Rollback if something breaks
sudo nixos-rebuild switch --rollback
# Garbage collection (manual)
nix-collect-garbage -dUse direct toplevel builds to validate host composition:
nix flake check --all-systems --no-write-lock-file
nix build .#nixosConfigurations.acer-swift.config.system.build.toplevel --no-link
nix build .#nixosConfigurations.lenovo.config.system.build.toplevel --no-link
nix build .#nixosConfigurations.msi-ms7758.config.system.build.toplevel --no-linkBuild and publish NixOS workstation images as OCI containerDisk artifacts to Harbor:
just build # Build qcow2 image
just publish # Publish as OCI containerDisk to Harbor
just release # Build + publish in one step
just harbor-login # First-time Harbor login
just image-info # Show published image metadataOr using the build script directly:
./scripts/build-workstation-image.sh workstation-template kubevirt
./scripts/build-workstation-image.sh workstation-template qcowRelated files:
hosts/workstation-template/modules/homelab/workstation-image.nixJustfile- See knowledge-vault:
~/knowledge-vault/Infrastructure/Concepts/workstation-images.md
Use this sequence to reproduce the same pattern in your own repo:
- Fork/clone and rename host directories under
hosts/for your machines. - Update identity defaults in
lib/users.nix(git name/email, SSH keys). - Copy a host template (
hosts/acer-swift/orhosts/lenovo-21CB001PMX/) and editvariables.nix,configuration.nix,home.nix. - Add one distribution declaration per host in
flake-modules/hosts/<name>.nix. - Keep reusable behavior in
modules/roles/*.nixandmodules/core/*.nix; avoid host-specificspecialArgs. - If using secrets, update recipients in
secrets/.sops.yamland re-encrypt withsops updatekeys. - Run the validation commands above before every push.
- https://github.com/hercules-ci/flake-parts
- https://flake.parts/options/flake-parts-modules.html
- https://github.com/mightyiam/dendritic
- https://discourse.nixos.org/t/dendrix-dendritic-nix-configurations-distribution/65853
docs/hosts/msi-ms7758.md
From one Linux host, deploy to another host over SSH:
# Example: deploy acer-swift from lenovo
nixos-rebuild switch \
--flake .#acer-swift \
--target-host lukas@192.168.10.124 \
--sudo \
--ask-sudo-passwordNotes:
--use-remote-sudois deprecated; use--sudo.- Use
--ask-sudo-passwordwhen remote sudo requires a password. - If hostnames are flaky, target by IP.
Common failure:
sudo: a terminal is required to read the password
Fix: rerun with --ask-sudo-password.
SSH security is centralized in reusable modules, with host-specific values in hosts/<name>/variables.nix.
modules/core/services.nixmodules/core/network.nixmodules/core/users.nix
Current policy:
- Key-only SSH auth (
PasswordAuthentication = false) - No root SSH login (
PermitRootLogin = "no") - Allowed SSH users are explicit (
AllowUsers = [ username ]) - SSH firewall policy allows only LAN CIDR + loopback
- Authorized keys come from
lib/users.nixby default, with optional host override (sshAuthorizedKeys)
Per-host required variables:
# hosts/<name>/variables.nix
{
username = "lukas";
}Default source of SSH keys is lib/users.nix:
# lib/users.nix
{
lukas.sshKeys = [
"ssh-ed25519 AAAA... controller-key"
];
}Optional per-host override (only when needed):
# hosts/<name>/variables.nix
{
sshAuthorizedKeys = [
"ssh-ed25519 AAAA... override-for-this-host-only"
];
# Optional LAN override (default: 192.168.10.0/24)
lanCidr = "192.168.20.0/24";
}After changing SSH policy, always apply locally first on the target machine to avoid lockout:
sudo nixos-rebuild switch --flake .#<host>System auto-updates weekly (Sunday 3 AM), runs garbage collection monthly, and optimizes the store weekly. Configured in modules/core/automation.nix.
Boot NixOS ISO (GNOME/Plasma for WiFi GUI), then:
nix-shell -p git
git clone <repo-url> /mnt/home/nixos-config && cd /mnt/home/nixos-config
# Create host config (copy from existing machine)
mkdir -p hosts/<name>
cp /mnt/etc/nixos/hardware-configuration.nix hosts/<name>/
cp hosts/acer-swift/{configuration.nix,home.nix,variables.nix} hosts/<name>/
# Edit variables.nix + configuration.nix, then add a host declaration under flake-modules/hosts/- Create
hosts/<name>/by copying an existing host - Update
variables.nix(apps, desktop, hardware, SSH hardening vars) - Update
configuration.nixif the hardware/roles differ - Add
flake-modules/hosts/<name>.nixwithconfigurations.nixos.<flake-name> - No registry edits are needed for Home Manager modules if
hosts/<name>/home.nixexists (auto-discovered byflake-modules/20-module-registry.nix)
Use hosts/acer-swift and hosts/lenovo-21CB001PMX as examples.
Minimum secure defaults for new hosts:
{
username = "lukas";
# hostname, desktop, hardware, roles...
}SSH keys are inherited from lib/users.nix by default.
Use modules + roles, not ad-hoc host edits.
- Create a reusable service module in
modules/<domain>/<service>.nix. - Expose an option and guard config with
mkIf:- Example:
options.homelab.<service>.enable = mkEnableOption "...";
- Example:
- Add required ports/rules in the module itself (firewall stays close to service).
- Attach module via a role (
modules/roles/*.nix) if shared by multiple hosts. - Enable that role (or service option) in
hosts/<name>/configuration.nix. - Build/apply locally, then remote deploy if needed.
Template:
{ config, lib, ... }:
with lib;
let
cfg = config.homelab.myservice;
in
{
options.homelab.myservice.enable = mkEnableOption "My service";
config = mkIf cfg.enable {
# service config
};
}- Install base NixOS from USB on the new host and ensure network +
sshdare up. - From Lenovo, fetch the host SSH key and convert to age recipient:
nix shell nixpkgs#ssh-to-age nixpkgs#openssh -c sh -c 'ssh-keyscan -t ed25519 <new-hostname-or-ip> 2>/dev/null | ssh-to-age' - Add that
age1...recipient tosecrets/.sops.yamlunderhomelab/.*\.yaml$. - Re-encrypt homelab secrets:
cd secrets sops updatekeys -y homelab/k3s.yaml homelab/cloudflare.yaml - Commit secret recipient updates:
cd .. git add secrets/.sops.yaml secrets/homelab/k3s.yaml secrets/homelab/cloudflare.yaml git commit -m "Add <new-host> SOPS recipient"
- Add host files:
hosts/<new-host>/variables.nixhosts/<new-host>/configuration.nixhosts/<new-host>/home.nixhosts/<new-host>/hardware-configuration.nix
- Register host in
flake-modules/hosts/<flake-host-name>.nix. - Apply on the new host:
sudo nixos-rebuild switch --flake .#<flake-host-name> - Verify decryption:
sudo journalctl -u sops-nix -b --no-pager | tail -n 40
Only add secret-dependent roles (homelab-server / homelab-agent) after step 4 is done.
| What | Where |
|---|---|
| Theme & colors | modules/themes/Catppuccin/default.nix |
| Wallpaper | assets/wallpapers/ |
| Git credentials | lib/users.nix |
| VSCode settings | dotfiles/vscode/ |
| Hyprland keybinds | modules/desktop/hyprland/ |
| i3 keybinds | modules/desktop/i3/home.nix |
| Desktop stacks | See knowledge-vault: ~/knowledge-vault/Infrastructure/Concepts/desktop-specialisation.md |
These have been helpful in understanding Nix:
- NixOS Manual
- Home Manager Manual
- Nix Pills (language fundamentals)
- Stylix (theming)
- Hyprland Wiki
This setup is inspired by Sly-Harvey/NixOS. Thanks for sharing a clean, modular reference repo.