Nix Config
This is my personal NixOS configuration using Nix flakes. The README is mainly generated by AI for future myself because I'm forgetful.
Architecture
This configuration uses a modular architecture built on top of flake-parts:
Directory Structure
/flake.nix: Entry point for the flake, definesnixosConfigurations,darwinConfigurations, anddeploy.nodes./unit: Modular configuration units that can be composed together./unit/default.nix: Collects and exports all units and presets./unit/home/*: Home-manager units for user-space configuration./unit/sys/*: System-level units (NixOS or nix-darwin)./unit/preset: Predefined collections of units (bare, core, local, server, gui).
/system: OS-specific system configurations./system/shared: Shared configuration across all systems./system/darwin: macOS-specific configuration./system/nixos-desktop: NixOS desktop configuration./system/nixos-server: NixOS server configuration.
/machine: Machine-specific configurations.- Desktop machines: Atlas, Everest
- Darwin machines: Fuji, Marcy
- Servers: Colden, LUX, LAX, EWR, HEL, HND, YUL
- Special: ProxmoxLXC (template for LXC containers), Minimum (minimal config)
/secrets: Encrypted secrets managed withgit-crypt./static: Static files like GPG and SSH public keys.
Key Concepts
Units
Units (./unit/{home/*,sys/*}) are modules that can be imported directly. They are organized into:
- Home units: User-space configuration
- System units: OS-level configuration
- Presets: Pre-composed collections of units for different use cases:
bare: Minimal CLI environmentcore: Essential command-line toolslocal: Full local development environment, shared across local NixOS and Darwinserver: Server-optimized configurationgui: Desktop GUI applications, some are Linux specific
Systems
Systems (./system/*) import presets and system units, then add OS-specific but machine-agnostic configurations. They define the baseline for each operating system type (Darwin, NixOS Desktop, NixOS Server).
Machines
Machines (./machine/*) import their corresponding system configuration and add machine-specific settings like:
- Hardware configuration
- Hostname and networking
- User accounts
- Machine-specific services
Build Functions
The flake defines specialized builders:
mkDarwinSystem: Builds macOS systems usingnix-darwinmkLinuxDesktop: Builds NixOS desktop systems with GUI supportmkLinuxServer: Builds NixOS server systemsmkLinuxService: Builds specialized service containers for Proxmox LXC
External Inputs
- nixpkgs: Tracks
nixpkgs-unstable - home-manager: User environment management
- nix-darwin: macOS support
- flakes: Personal package overlay
- rust-overlay: Rust toolchain management
- disko: Declarative disk partitioning
- deploy-rs: Remote deployment tool
- lanzaboote: Secure boot support
- zen-browser: Privacy-focused browser
- nixos-generators: Generate various system images (e.g., Proxmox LXC)
- vscode-server: Remote VS Code support
Usage
Local Activation
Just run rb anywhere.
Enter the development shell to make the pinned Infisical CLI available:
nix develop
Before rebuilding, rb fetches secrets with the Infisical CLI. Authenticate the
CLI and link this directory to a project with infisical init (or provide the
usual Infisical machine-identity environment variables). Dotted secret names
form the Nix attribute path: for example, github.oauth_token becomes
secrets.github.oauth_token. Infisical values override matching values from
secrets/secrets.nix for that evaluation only.
The equivalent flake command is:
nix run .#activate
Both commands stream the root-folder export into a root-owned 0600 file inside
a root-only temporary directory under /var/run. They invoke the rebuild with
impure evaluation and remove the file and directory afterward.
Import a JSON object into Infisical with:
printf '%s\n' '{"github":{"oauth_token":"secret"}}' \
| ./scripts/import-infisical-secrets.sh --env prod
Nested objects become dotted root-level secrets, so this example writes the
Infisical secret github.oauth_token. Activation expands it back into a nested
Nix attribute set. Every Infisical value is stored as JSON text, including quoted
JSON strings, so activation can restore its exact type with fromjson. All
values are staged in permission-restricted temporary files and sent in one
infisical secrets set call using name=@file arguments.
Remote Deployment
Remote servers are deployed using deploy-rs:
deploy .#<machine-name>
Building Images
Generate a Proxmox LXC template:
nix build .#proxmox-lxc
Notes
- Units (
./unit/{home/*,sys/*}) are "bare" in the sense that they can output to flake directly, where Machines (./machine/*) are not because they are wrapped by system declarations, e.g.,nixpkgs.lib.nixosSystem/nix-darwin.lib.darwinSystem. - Units are imported in
flake.nixasunit.{home,sys}, in which home units are further collected intounit.preset.{bare,core,local,server,gui}to form five "profiles"; all of which are passed down to systems and machines config withspecialArgsandhome-manager.extraSpecialArgs. - Systems (
./system) imports aforementioned "profiles" andsysunits, then add machine-agnostic but os-dependent configurations. - Machines (
./machine) imports corresponding systems andsysunits, then add machine-specific configurations. deploy-rsis used to push local changes to remote machines (configs live under.#deploy.nodes).- Secrets are managed with
git-cryptand keys are encoded withbase64. Decode withecho $KEY | base64 -d.
Invariants
- This config MUST live under
$HOME/.nix-config