Home Lab Design Specifications
This directory contains design specifications for various components of the home lab infrastructure. These specifications focus on architecture, security, and testing rationale before code implementation.
Specifications Directory Index
| Specification | Description | Current Implementation Status |
|---|---|---|
| Home Lab Bootstrapping | Global VM installation infrastructure: Nix-native custom installer ISO, secure bootstrap key loading with Git-tracking guardrails, and nixos-anywhere. |
Fully Implemented |
| NixOS VMs on Proxmox | Reusable framework for NixOS VMs: the proxmox-vm role, host structure with Disko layouts, and the Terraform VM provisioning pattern. |
Fully Implemented |
| Declarative Integration Testing | Design of the NixOS test generator framework (make-test.nix), dynamic test discovery, and parallel GHA matrix CI pipeline. |
Fully Implemented |
| NixOS LXC Containers on Proxmox | Reusable framework for NixOS LXC containers: the proxmox-lxc role, system.build.tarball templates, and the Terraform provisioning pattern. |
Fully Implemented |
| NAS LXC Container | NixOS LXC containers on each Proxmox node exposing host ZFS datasets as SMB shares via bind mounts. Builds on the proxmox-lxc framework. |
Fully Implemented |
Specifications to write and TODOs
- Generate a Home Lab bootstrapping keypair.
- Fully automate Terraform runs. Reference: Running Terraform in automation.
- Fully automate provisioning and configuration of new hosts.
- Minimize external dependencies:
- NixOS ISO server host
- Terraform provider registry
- Nix tests
- Modularize the integration-test generator: move the per-service test
fragments (SSH, QEMU guest agent, comin, Samba, ...) out of
config/nix/tests/make-test.nix— for example placing each fragment next to its role — so the generator stays maintainable as service coverage grows. Do it for all services at once to avoid a split paradigm. - Check that configured users are present
- Check that configured users have their SSH keys authorized (reuse the existing bootstrap key check because it already does most of the stuff we need for this check).
- Modularize the integration-test generator: move the per-service test
fragments (SSH, QEMU guest agent, comin, Samba, ...) out of
-
Stable serial adapter assignment:
- Create a udev rule:
echo 'SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", SYMLINK+="zigbee_dongle"' | sudo tee /etc/udev/rules.d/99-zigbee.rules - Change the mapping in Docker
-
Logs:
Error response from daemon: error gathering device information while adding custom device "/dev/serial/by-id/usb-ITEAD_SONOFF_Zigbee_3.0_USB_Dongle_Plus_V2_20220708144056-if00": no such file or directory pi@raspberrypi2:~ $ ls /dev/serial/by-id usb-1a86_USB_Single_Serial_54DD003512-if00
- Create a udev rule:
-
Move monitoring stack from the home_lab_node role to the home_lab_monitoring role.
- NixOS VMs (NixOS VMs on Proxmox): factor the per-host
Terraform VM resources into a shared module (or
for_eachover a host map) once a second NixOS VM exists, so the reference pattern is enforced by code rather than by convention. - Cross-host workloads backup.
- NAS (NAS LXC Container):
- NFS support: Re-introduce NFS sharing alongside SMB. Evaluate
nfs-kernel-serverin a privileged container versus the user-space NFS-Ganesha server, which can run in an unprivileged container. - Automated template upload: Replace the local-file push
(
proxmox_virtual_environment_filepointing at the local build artifact, per the framework pattern) withproxmox_virtual_environment_download_filepulling the template from a published URL, removing the need for a locally built artifact atterraform applytime. - Samba performance tuning: Benchmark before adding any tuning to the
nasrole. Modern Samba enables AIO by default, and the classic knobs interact (a non-zeroaio write sizedisablesmin receivefile size), so tuning without measurement is at best a no-op. - GitOps requires the
cominrole per host: comin needs a hostname at build time, so it cannot ride in the shared, hostname-less bootstrap template (see template generation). Each NAS host'sconfiguration.nixmust therefore import thecominrole itself, which is installed by the one-timenixos-rebuild switchhandoff. True zero-touch first-boot GitOps would require working around comin's build-time hostname model. - Samba password automation: Replace the imperative
smbpasswdstep (SMB user management) with a mechanism/material split that keeps secrets out of the public repository (committing encrypted secrets — e.g.sops-nixciphertext — was considered and rejected: this repository's policy keeps even encrypted secrets untracked, and public Git history is immortal). Design: thenasrole ships a oneshot systemd unit that, on every activation, reads a password file from a well-known path and pipes it intosmbpasswd -s -a ferrarimarco; the Ansible layer that already manages the Proxmox nodes writes that file (root-only,0600) to/var/lib/samba-state/nas-pveN/smb-passwordfrom a vaulted (untracked) variable, so the container's existing/var/lib/sambabind mount delivers it. Container recreation then self-heals the password database, rotation is an Ansible run plus a unit restart, and disaster recovery reduces to the local Ansible vault, as for every other secret in the lab. - SMB service discovery: Enable Samba's WS-Discovery or Avahi for automatic share browsing on Windows and macOS clients.
- Static IP migration: Transition from DHCP to static IP assignments defined in the NixOS configuration once the network spec is written.
- Terraform-managed ZFS pools (evaluated 2026-08, deferred): the
bpg/proxmoxprovider (since 0.111.x) offersproxmox_node_disk_zfsfor node ZFS pool lifecycle. Transitioning the pool layer of thesetup_disksrole (see dataset mount points) to it was evaluated and rejected for now: its pool attributes (devices,raidlevel,ashift,compression) are write-only, so the Terraform config would be the same unverified documentation thezfs_poolsinventory already is, with no drift detection; the provider manages pools only, so datasets and mount-point ownership would stay in Ansible, splitting the ZFS layer across two tools; and with the local Terraform state backend, losing state would invert the deliberate "pools are asserted, never created" stance into a pool-creation attempt on data-bearing devices at the next apply. Revisit when the provider gains readable pool attributes (real drift detection) or dataset management, or when a durable remote state backend is in place. - Single source of truth for shares: Derive the Samba share exports
(NixOS), the bind mounts (Terraform), and the host datasets (Ansible
zfs_datasets, dataset mount points) from one data structure — for example a Nix attrset emitted totfvarsvianix eval— so each share is declared once and the three halves cannot drift (see per-host shares).
- NFS support: Re-introduce NFS sharing alongside SMB. Evaluate