My personal Infrastructure Lab, fully declarative and reproducible — powered by NixOS Flakes.
| Service | URL |
|---|---|
| Server monitor | monitor.yzlab.eu.org |
| Status page | status.yzlab.eu.org |
This code repo is a single source of truth for every NixOS machine in my homelab. Every host, every service, every system option is defined in code here. No manual configuration, no configuration drift — if it's not in this repo, it doesn't exist on the machine.
The stack is built around NixOS Flakes with a focus on:
- Reproducibility — identical builds, every time, on any machine
- Declarative provisioning — fresh host to fully configured in one command
- Secret safety — encrypted secrets committed directly to Git
- Operational simplicity — complex operations wrapped into short
justcommands
Current scale: 10+ hosts, 50+ self-hosted services, encompassing VPS/VDS instances across multiple cloud providers, local bare-metal server hosts, and virtual machines.
Most homelab setups drift over time — packages installed manually, config files tweaked in-place, undocumented one-off fixes. NixOS eliminates this entirely:
- Atomic upgrades and rollbacks — switch generations with a single command; roll back just as easily
- Reproducible builds —
flake.lockpins every dependency; the same flake always produces the same system - No imperative state — the system is a pure function of the configuration; no hidden state to worry about
- Dev shell included —
nix developdrops you into a shell with all tooling (sops,nixos-rebuild,alejandra, etc.) without installing anything globally
| Layer | Tool | Role |
|---|---|---|
| OS | NixOS | Declarative, atomic Linux |
| Flake framework | flake-parts | Modular flake composition |
| Disk layout | disko | Declarative disk partitioning |
| Remote install | nixos-anywhere | Zero-touch provisioning over SSH |
| Secrets | sops-nix + age | Encrypted secrets in Git |
| Task runner | just | Ergonomic command automation |
| Formatter | alejandra + deadnix | Nix code quality |
| Compose bridge | compose2nix | Docker Compose → Nix translation |
yzlab/
├── flake.nix # Flake entry point, input declarations
├── flake.lock # Locked dependency graph
├── justfile # Automation commands
├── .sops.yaml # SOPS encryption rules
├── hosts/ # Per-host NixOS configurations
│ └── <hostname>/
│ ├── default.nix
│ └── hardware.nix
├── modules/ # Reusable NixOS modules
│ └── private/ # SOPS-encrypted secrets (safe to commit)
└── pkgs/ # Custom Nix packages
Each host under hosts/ is a self-contained NixOS system definition. Hardware configuration is auto-generated during provisioning via nixos-generate-config and committed alongside the declarative config. Shared behaviour lives in modules/, keeping host configs lean and focused on machine-specific concerns.
Secrets are encrypted with SOPS using an age key and committed directly into modules/private/. The .sops.yaml defines which files are encrypted and which keys can decrypt them.
# .sops.yaml
keys:
- &admin_yonzilch age1yzce0p...
creation_rules:
- path_regex: modules/private/.*
key_groups:
- age:
- *admin_yonzilch- Nix with flakes enabled
justinstalled- An age key at
~/.config/sops/age/keys.txt(generate withjust keygen)
just keygen # Generate a new age key via rage
just update # Update all flake inputs
just upgrade # Rebuild and switch the local host in-place
just build <hostname> # Build a host configuration (no deploy)
just build-vm <hostname> # Build and launch as a local VM for testing
just deploy <hostname> # Deploy to a running remote host (nixos-rebuild switch)
just deploy-rb <hostname> # Same, but build on the remote machine
just anywhere <hostname> # Provision a fresh host from scratch (nixos-anywhere)
just anywhere-lb <hostname> # Same, build locally before sending
just anywhere-vm <hostname> # Dry-run in a local VM
just enc <hostname> # Encrypt secrets for a host
just dec <hostname> # Decrypt secrets for a host
just eac # Encrypt all secrets
just dac # Decrypt all secrets
just format # Format all Nix files (alejandra + deadnix)
# 1. Create host config
mkdir -p hosts/<hostname>
# ... write hosts/<hostname>/default.nix
# 2. Generate age key if you haven't already
just keygen
# 3. Provision — hardware-config is auto-generated and applied
just anywhere <hostname>The anywhere command handles everything: updating flake.nix with the target hostname, auto-generating hardware configuration via nixos-generate-config, and deploying over SSH in a single step.
just deploy <hostname>That's it. NixOS atomically switches to the new generation; if anything goes wrong, the previous generation is intact and bootable.