homelab

Flake-based NixOS config. Host: jupiter (ZimaBlade, NAS + services).

Structure

flake.nix                           # inputs (nixpkgs, disko) + nixosConfigurations
jupiter/configuration.nix           # real host: imports + bootloader + data mount
jupiter/disk-config.nix             # disko: OS-disk partitions + filesystems
jupiter/hardware-configuration.nix  # PLACEHOLDER — kernel modules, regenerate on target
jupiter/services.nix                # shared: users, ssh, samba, containers, caddy
jupiter/vm.nix                      # VirtualBox test image (jupiter-vbox)

Two configs from one service definition: jupiter (real host, disko-partitioned) and jupiter-vbox (test OVA). Both import services.nix.

Test in VirtualBox (no hardware needed)

nix build .#nixosConfigurations.jupiter-vbox.config.system.build.virtualBoxOVA
VBoxManage import result/*.ova --vsys 0 --vmname jupiter-vbox
VBoxManage startvm jupiter-vbox --type headless

Login darman / test. Forward ports with VBoxManage modifyvm ... --natpf1.

First install on the ZimaBlade — nixos-anywhere + disko

Wipes the OS disk and installs the flake over SSH. No USB needed if the box already runs Linux (ZimaOS) reachable by root SSH — nixos-anywhere kexecs into an installer, partitions via disko, installs.

⚠️ The OS disk in disk-config.nix is WIPED. Set device to the OS disk ONLY (by-id). Back up / physically identify the NAS data disk first — it must NOT appear in disko. lsblk -o NAME,SERIAL,SIZE,MODEL to identify.

  1. Set the real OS disk id in jupiter/disk-config.nix (ls -l /dev/disk/by-id), and the data-disk mount in configuration.nix.
  2. Add your login SSH pubkey to users.users.darman.openssh.authorizedKeys.keys.
  3. Set the real samba password:
    export SOPS_AGE_KEY_FILE=~/.config/sops/age/keys.txt
    nix shell nixpkgs#sops -c sops secrets/jupiter.yaml   # edit, commit
    
  4. Stage the pre-generated host key so sops can decrypt on boot #1 (private key lives off-repo in ~/.config/homelab/jupiter/):
    install -Dm600 ~/.config/homelab/jupiter/ssh_host_ed25519_key \
      /tmp/extra/etc/ssh/ssh_host_ed25519_key
    install -Dm644 ~/.config/homelab/jupiter/ssh_host_ed25519_key.pub \
      /tmp/extra/etc/ssh/ssh_host_ed25519_key.pub
    
  5. Run from your laptop:
    nix run github:nix-community/nixos-anywhere -- \
      --flake .#jupiter \
      --extra-files /tmp/extra \
      --generate-hardware-config nixos-generate-config ./jupiter/hardware-configuration.nix \
      --target-host root@<zimablade-ip>
    
    --extra-files plants the host key before first boot (its age identity is already a recipient in .sops.yaml, so /run/secrets/samba_password decrypts on boot #1). --generate-hardware-config pulls the target's real kernel modules into the placeholder. Commit the result. Reboot into NixOS.

Manual alternative (USB ISO): boot installer, disko the disk, then nixos-install --flake .#jupiter.

Rebuild after changes (the daily loop)

# from laptop, build + activate on jupiter over SSH:
nixos-rebuild switch --flake .#jupiter \
  --target-host darman@jupiter --use-remote-sudo

Rollback: nixos-rebuild switch --rollback, or pick a prior generation at boot.

Adding a service

Copy the whoami block in oci-containers.containers, swap image/ports/volumes. Native NixOS module exists for many apps (Nextcloud, Jellyfin, Grafana...) — prefer services.<app> over a container when available. Add a caddy virtualHosts block to expose it.

Notes

  • Backend is Podman with dockerCompatdocker CLI works, no daemon.
  • Samba keeps its own password DB. services.samba never sets it; a systemd oneshot (samba-smbpasswd) provisions it. Host reads the password from /run/secrets/samba_password (sops-nix); the VM falls back to plaintext /etc/samba/smb-password.
  • Secrets: secrets/jupiter.yaml is age-encrypted (safe to commit) to two recipients in .sops.yaml — the admin key (edit on laptop, ~/.config/sops/age/keys.txt) and the jupiter host key (derived from its SSH host key via ssh-to-age, decrypts at runtime). Private keys live off-repo and are gitignored. Rotate/add recipients with sops updatekeys.
  • Data disk: plain fileSystems."/mnt/data" in configuration.nix — kept out of disko so it is never formatted. Reference by by-id / by-uuid.
  • system.stateVersion = 26.05, install-time schema. Do NOT bump on upgrades.
  • Terraform is not used: a single bare-metal box has no provider API. disko + nixos-anywhere cover provisioning natively.
S
Description
No description provided
Readme
32 MiB
Languages
Nix 40.1%
QML 30.5%
Shell 25.9%
Python 3.5%