Files
nixos-config/AGENTS.md
2026-01-02 15:12:26 +01:00

6.3 KiB

NIXOS CONFIGURATION KNOWLEDGE BASE

Generated: 2025-12-31 16:13:40 UTC
Commit: ebc8291
Branch: HEAD

OVERVIEW

Personal NixOS configuration managing 6 hosts (4 servers, 2 desktops) using flakes, agenix secrets, and feature-based home-manager setup.

STRUCTURE

./
├── flake.nix              # Main entry: host definitions, inputs, outputs
├── secrets.nix            # Agenix public key mappings
├── hosts/
│   ├── common/            # Shared: base config, users, extraServices, ports
│   ├── m3-atlas/          # Server: 20+ containerized services with Traefik
│   ├── m3-helios/         # Server: AdGuard, internal routing
│   ├── m3-ares/           # Desktop: NVIDIA GPU, Btrfs
│   ├── m3-kratos/         # Desktop: AMD GPU, ZFS
│   └── m3-aether/         # Cloud VM
├── home/
│   ├── common/            # Home-manager base config
│   ├── features/          # Modular feature toggles (cli, desktop, coding)
│   └── m3tam3re/          # Per-host user configs
├── modules/               # Custom NixOS/home-manager modules
├── overlays/              # Package overlays (stable, locked, pinned, master)
├── pkgs/                  # Custom package definitions
└── secrets/               # Agenix encrypted .age files (19 secrets)

WHERE TO LOOK

Task Location Notes
Add new host flake.nix + hosts/<name>/ Copy template from m3-atlas (server) or m3-ares (desktop)
Add service to m3-atlas hosts/m3-atlas/services/ See containers/ for Podman + Traefik pattern
Configure desktop features home/features/desktop/ Feature toggles with mkEnableOption
Add CLI tool home/features/cli/ Fish + Nushell integration expected
Manage secrets secrets.nix + agenix -e SSH keys defined in secrets.nix
Define ports hosts/common/ports.nix Centralized port registry
Add user hosts/common/users/ Shared across all hosts
Custom packages pkgs/default.nix Exposed via flake outputs

CONVENTIONS

Secrets (agenix)

  • Create: agenix -e secrets/<name>.age after adding keys to secrets.nix
  • Reference: config.age.secrets.<name>.path in service configs
  • Pattern: Service env files use environmentFiles = [config.age.secrets.<service>-env.path]

Service Organization

  • Native services: hosts/<host>/services/<service>.nix
  • Containers: hosts/<host>/services/containers/<service>.nix
  • Traefik integration: All m3-atlas services include dynamic config for SSL + routing
  • Networking: Containers use dedicated web network (10.89.0.0/24) with static IPs

Port Management

  • Registry: All ports defined in hosts/common/ports.nix
  • Access: config.m3ta.ports.get "service-name"
  • Convention: Internal services use 3000-3020 range

Home-Manager Features

  • Enable: features.<category>.<feature>.enable = true in user config
  • Categories: cli, desktop, coding
  • Pattern: Features are opt-in modules with default.nix aggregators

Multiple nixpkgs Inputs

  • stable: 25.11 release
  • locked/pinned: Specific commits for compatibility
  • master: Bleeding edge
  • m3ta-nixpkgs: Custom local overlay at path:/home/m3tam3re/p/nix/nixpkgs

COMMANDS

# Build/deploy specific host
sudo nixos-rebuild switch --flake .#m3-ares

# Build/deploy current host
sudo nixos-rebuild switch --flake .#$(uname -n)

# Home-manager update
home-manager --flake . switch

# Update all flake inputs
nix flake update

# Add/edit secret
agenix -e secrets/<name>.age

# Infrastructure shell (OpenTofu)
nix develop .#infraShell

# Check configuration (no activation)
nixos-rebuild dry-build --flake .#<hostname>

TRAEFIK PATTERNS (m3-atlas only)

SSL Termination

  • Provider: Godaddy DNS challenge
  • Cert storage: /var/lib/traefik/acme.json
  • Config: hosts/m3-atlas/services/traefik.nix

Service Integration Template

services.traefik.dynamicConfigOptions.http = {
  services.<name>.loadBalancer.servers = [{ url = "http://127.0.0.1:<port>"; }];
  routers.<name> = {
    rule = "Host(`<subdomain>.m3ta.dev`)";
    service = "<name>";
    tls.certResolver = "godaddy";
  };
};

Container Pattern

  • Network: --network=web --ip=10.89.0.<sequential>
  • Ports: Bind localhost only (127.0.0.1:<external>:<internal>)
  • Database access: --add-host=mysql:10.89.0.1 (gateway IP)

HOST ROLES

Host Type Hardware Purpose
m3-atlas Server x86_64, disko 20+ services, Traefik hub, PostgreSQL, MySQL
m3-helios Server x86_64, disko AdGuard DNS, internal routing
m3-ares Desktop NVIDIA, Btrfs Personal workstation, n8n, PostgreSQL
m3-kratos Desktop AMD, ZFS Workstation, mem0, PostgreSQL
m3-aether Cloud QEMU General purpose VM
m3-daedalus Laptop home-only Portable (no full NixOS config)

ANTI-PATTERNS (THIS PROJECT)

  • DON'T add secrets to secrets/ without updating secrets.nix public keys
  • DON'T hardcode ports - use config.m3ta.ports.get or add to registry
  • DON'T create containers outside the web network on m3-atlas
  • DON'T skip Traefik config for public-facing services on m3-atlas
  • DON'T bypass extraServices flags - use hosts/common/extraServices/ pattern
  • DON'T commit unencrypted secrets or test with real credentials

UNIQUE TO THIS CONFIG

  • Custom m3ta-nixpkgs: Local overlay for unreleased/patched packages
  • extraServices abstraction: Boolean flags to toggle Podman, Ollama, virtualisation per host
  • Mythological naming: All hosts named after Greek mythology
  • Dual domain strategy: New services on m3ta.dev, legacy redirects from m3tam3re.com
  • Per-host nixpkgs versions: Different hosts can use different nixpkgs commits via specialArgs
  • Container IP registry: Static IP assignments in 10.89.0.0/24 subnet for predictable networking

NOTES

  • m3-atlas is the service hub - most complex configuration
  • Secrets require host SSH keys defined in secrets.nix before agenix -e works
  • Fish and Nushell both configured - choose per-user with shell aliases
  • Color scheme (Dracula) applied via nix-colors across all visual tools
  • See subdirectory AGENTS.md for deep dives on containers, desktop features, CLI tools