Skip to main content

Overview

The Data Fortress is built on a foundation of clear design principles that guide every architectural decision. These principles ensure the infrastructure remains maintainable, reproducible, and stable at scale.

Core Tenets

1. Declarative Everything

If it’s not in code, it doesn’t exist. Every aspect of the infrastructure—from system configurations to user environments—must be declared in version-controlled Nix expressions. This eliminates drift, ensures reproducibility, and provides a complete audit trail.
Manual changes made directly to systems will be overwritten on the next deployment. All modifications must go through the configuration repository.
Benefits:
  • Complete infrastructure as code
  • Git history serves as change log
  • Easy rollbacks to any previous state
  • No undocumented “tribal knowledge”

2. Single Command Invocation

Deployment and updates should be one command. Complexity should be hidden behind simple, idempotent commands. Whether deploying a new system or updating an existing one, the process should be straightforward:
# Deploy a NixOS system
nixos-rebuild switch --flake .#hostname

# Deploy a Home Manager configuration
home-manager switch --flake .#user

# Deploy to Android device
nix-on-droid switch --flake .#device
The same command works for initial deployment and subsequent updates. Nix’s declarative nature ensures the system converges to the desired state.

3. Dynamic Discovery

The system automatically finds code. You shouldn’t have to manually import every new file. Traditional Nix configurations require manually importing every module and configuration file. This homelab uses automatic discovery functions that scan directories and build configurations dynamically. What this means in practice:
  • Create a new directory in systems/ → automatically becomes a NixOS configuration
  • Add a file to homes/ → automatically available as a Home Manager configuration
  • Drop a module in modules/nixos/ → automatically imported and available
Discovery eliminates boilerplate and reduces cognitive overhead. You can focus on writing configurations instead of managing imports.
See Dynamic Discovery for implementation details.

4. Stability

nix flake check is the law. Every change must pass nix flake check before being merged or deployed. This command validates:
  • All NixOS configurations evaluate successfully
  • All Home Manager configurations evaluate successfully
  • All Nix-on-Droid configurations evaluate successfully
  • Code formatting is correct
  • Pre-commit hooks pass
# Always run before deploying
nix flake check
CI/CD pipelines enforce this rule. Pull requests cannot be merged if nix flake check fails.
Why this matters:
  • Catches errors before deployment
  • Prevents broken configurations from reaching production
  • Ensures all systems remain buildable
  • Forces evaluation of lazy Nix expressions

Design Implications

Hermetic Builds

All builds are hermetic and reproducible thanks to Nix Flakes. The flake.lock file pins every input to exact revisions, ensuring:
  • Identical builds on different machines
  • Ability to reproduce historical configurations
  • Protection against supply chain attacks

Modularity

Configurations are composed from reusable modules:
  • System-level modules in modules/nixos/
  • User-level modules in modules/home/
  • Android modules in modules/droid/
Modules encapsulate specific functionality and can be mixed and matched per system or user.

Separation of Concerns

The directory structure enforces clear boundaries:
LayerLocationScope
System configurationsystems/Machine-level settings
User configurationhomes/Per-user environments
Reusable logicmodules/Shared functionality
Custom softwarepkgs/Package definitions
Utilitieslib/Helper functions

Zero Trust Secrets

Secrets are managed using agenix with encryption at rest:
  • Secrets never stored in plaintext
  • Encrypted with age keys derived from host SSH keys
  • Decrypted only at deployment time
  • Separate secrets per system/user

Philosophy in Practice

Adding a New System

  1. Create directory: systems/newhost/
  2. Add default.nix with configuration
  3. Optionally add meta.json for metadata
  4. Run nix flake check
  5. Deploy: nixos-rebuild switch --flake .#newhost
No manual imports required. The system is automatically discovered and built.

Adding a New User

  1. Create directory: homes/newuser/
  2. Add default.nix with Home Manager configuration
  3. Run nix flake check
  4. Deploy: home-manager switch --flake .#newuser
The user configuration is automatically detected and available.

Creating a Module

  1. Add file to modules/nixos/ or modules/home/
  2. Module is automatically imported
  3. Enable in system/user configuration
  4. Run nix flake check to validate
No manual module list maintenance.

Conclusion

These four principles—declarative everything, single command invocation, dynamic discovery, and stability—create an infrastructure that is:
  • Easy to understand and navigate
  • Simple to extend with new systems
  • Reliable through automated validation
  • Reproducible across environments
Every architectural decision in this homelab traces back to these core tenets.

Build docs developers (and LLMs) love