Nix flake for my personal machines — NixOS system + Home Manager configs for personal machines.
  • Nix 86.1%
  • Shell 8.4%
  • Python 3%
  • JavaScript 2.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-28 16:23:34 +01:00
android ssh: sign and authenticate through the session agent instead of Bitwarden's 2026-09-10 21:21:29 +01:00
home Use vpn for cremin.dev ssh 2026-09-28 16:23:34 +01:00
hosts Add Claude statusline 2026-09-28 16:16:23 +01:00
modules Add Claude statusline 2026-09-28 16:16:23 +01:00
pkgs storyteller-whisper: socket-activated whisper.cpp transcription on the desktop GPU 2026-09-10 21:21:51 +01:00
secrets pi-02: second Raspberry Pi 5 k3s agent 2026-09-11 19:21:27 +01:00
.gitignore Add configuration for Android Linux VM 2026-06-27 20:07:43 +01:00
CHEATSHEET.md docs: add NixOS cheatsheet 2026-06-13 15:55:38 +01:00
flake.lock Add Claude statusline 2026-09-28 16:16:23 +01:00
flake.nix pi5: Raspberry Pi vendor kernel from nixos-raspberrypi 2026-09-12 14:34:32 +01:00
README.md pi-02: second Raspberry Pi 5 k3s agent 2026-09-11 19:21:27 +01:00

NixOS machines

Declarative config for my NixOS machines. Multi-host flake: shared config in modules/, per-machine specifics in hosts/, user environment in home/. The repo is synced across machines by Syncthing, so every host builds from ~/Code/nixos directly.

Each host's default.nix imports ../../modules plus its own hardware-configuration.nix, then sets only what's machine-specific. The flake's mkHost adds nix-flatpak, home-manager, and agenix to every host. No conditionals — a machine either imports a module or it doesn't.

Day-to-day

The flake attribute is the hostname, so bare nixos-rebuild targets the right host:

sudo nixos-rebuild switch --flake /home/jonathan/Code/nixos#laptop
sudo nixos-rebuild build  --flake /home/jonathan/Code/nixos#laptop   # check without activating
nix flake update          --flake /home/jonathan/Code/nixos          # bump inputs
sudo nixos-rebuild switch --rollback                                 # previous gen

New .nix files are picked up automatically (not a git flake, so no git add needed).

Secrets (agenix)

The GitHub packages token lives encrypted in secrets/github-token.age, decrypted at boot to /run/agenix/github-token, and read into GITHUB_PACKAGES_TOKEN by zsh. Every host that consumes a secret must be a recipient in secrets/secrets.nix — get a host's pubkey with cat /etc/ssh/ssh_host_ed25519_key.pub.

cd secrets && nix run github:ryantm/agenix -- -e github-token.age   # edit
cd secrets && nix run github:ryantm/agenix -- -r                    # re-encrypt

modules/secrets.nix guards on pathExists, so the config still evaluates before the .age exists.

Home / dotfiles

home/jonathan.nix (home-manager): zsh + oh-my-zsh + starship, git, ssh, editorconfig, Syncthing, GNOME dconf. The system only enables zsh as a login shell; all shell config is here. Conflicting pre-existing files are moved to *.hm-bak on first switch. Syncthing's device list is filtered per host so a machine never lists itself; server is the introducer.

Adding a host

  1. Install NixOS (UEFI → systemd-boot).
  2. sudo nixos-generate-config --show-hardware-config > hosts/<name>/hardware-configuration.nix
  3. Write hosts/<name>/default.nix: bootloader, networking.hostName, system.stateVersion, and imports = [ ./hardware-configuration.nix ../../modules ].
  4. Add <name> = mkHost ./hosts/<name>; to flake.nix.
  5. Add the host's SSH host key to secrets/secrets.nix, then agenix -r.
  6. sudo nixos-rebuild switch --flake /home/jonathan/Code/nixos#<name>.

Each host needs its own hardware-configuration.nix — never copy one machine's to another.

pi-NN (Raspberry Pi 5 k3s agents)

Each Pi is a hostname and address in hosts/pi-NN/; everything else is modules/pi5-k3s-agent.nix + modules/pi5-boot.nix. Provisioned from an SD image rather than the installer. It's built from nixpkgs-unstable via binfmt emulation, so the building host needs boot.binfmt.emulatedSystems = [ "aarch64-linux" ] (the desktop has it). The Pi firmware loads the kernel directly (no U-Boot — it can't reach a USB disk on the Pi 5); modules/pi5-boot.nix explains the layout. There's no boot menu, so keep an eye on the HDMI console after a risky switch.

nix build .#pi-NN-image                      # -> result/sd-image/*.img
sudo dd if=result/sd-image/*.img of=/dev/sdX bs=4M conv=fsync status=progress
nixos-rebuild switch --flake .#pi-NN --target-host root@<address>   # thereafter

Each Pi's SSH host key was generated up front and copied onto the imaged disk's /etc/ssh so the k3s join token (secrets/k3s-token.age) decrypts on first boot. If a disk is ever re-imaged, either copy the same key back or add the new host key to secrets/secrets.nix and re-encrypt. The nodes join storage-01's cluster tainted arch=arm64:NoSchedule, so workloads must tolerate it (and select kubernetes.io/arch: arm64) to land there. After first boot, enrol in NetBird once with netbird up on the node.

host address
pi-01 10.0.1.40
pi-02 10.0.1.41
SSH host key, so update secrets/secrets.nix and run agenix -r, or boot-time
decryption will fail.