main

Imperative Configuration

Configuration for hosts not managed declaratively by NixOS.

Overview

This directory holds configuration for machines that run a traditional Linux distribution (Fedora, Debian) instead of NixOS. Two complementary approaches live here:

  1. Nix on top of the host OS — using the Determinate Nix installer with Home Manager for the user environment and Nix-generated host files where needed. This is the current, preferred approach. See aomi, kyushu, and nagoya.
  2. Idempotent bash scripts — self-contained bootstrap scripts for initial Nix installation and repository checkout.

Why this exists

Some systems can’t run NixOS directly:

  • Hardware or organizational constraints (e.g. IT-managed corporate laptop)
  • Transition periods before a full NixOS migration
  • Lightweight servers where a single script is enough

Directory Structure

imperative/
├── README.md           # This file
├── aomi/               # Fedora CSB laptop — Nix (system-manager + home-manager)
│   ├── README.md
│   └── bootstrap.sh
├── nagoya/             # Debian server — Determinate Nix + Home Manager
│   ├── README.md
│   └── bootstrap.sh
└── sakhalin/           # Fedora family workstation — minimal Nix + Home Manager
    ├── README.md
    └── bootstrap.sh

Current Hosts

aomi — Fedora CSB + Nix

  • OS: Red Hat CSB (Fedora), aarch64/x86_64 laptop (ThinkPad P1 Gen 3)
  • Type: Work desktop/laptop, IT-managed base OS
  • Approach: Nix (Determinate installer) with system-manager + home-manager
  • Components: WireGuard, Syncthing, shell, editors, dev tools
  • Bootstrap: bootstrap.sh

See aomi/README.md for details.

nagoya — Debian Server

  • OS: Debian, aarch64
  • Type: Server
  • Approach: Determinate Nix with a minimal Home Manager builder profile and Nix-generated host files
  • Components: shell, Nix development tools, and generated /etc/hosts / /etc/nix/nix.custom.conf; Debian manages existing services and networking
  • VPN IP: 10.100.0.80/24
  • Status: Active — bootstrap is intentionally limited to Nix, repository, generated host files, and Home Manager to preserve existing WireGuard setup.

See nagoya/README.md for details.

sakhalin — Fedora Workstation

  • OS: Fedora Workstation
  • Type: Family workstation
  • Approach: Determinate Nix with minimal standalone Home Manager and Nix-generated /etc/hosts, /etc/nix/nix.custom.conf, and WireGuard config
  • Components: shared shell baseline and Syncthing; WireGuard is enabled once its externally preserved private key is restored

See sakhalin/README.md for details.

Usage

Nix-managed hosts

cd ~/src/home

# Build and deploy generated host files where the host provides an artifact
nix build .#hostConfigs.<hostname>
sudo ./result/deploy

# Home Manager (shell, editors, development tools)
home-manager switch --flake .#<user>@<hostname>

Initial provisioning is done via the host’s bootstrap.sh. See the host README for the exact invocation.

Bootstrap a Nix-managed host

bash ./imperative/<hostname>/bootstrap.sh

Adding a New Host

Pick the approach that fits the machine:

Nix-managed (preferred)

  1. Add a homeConfigurations."<user>@<hostname>" entry in flake.nix.
  2. Add a hostConfigs.<hostname> output when generated host files are needed.
  3. Create imperative/<hostname>/bootstrap.sh to install Nix, check out the repository, and activate the minimal required configuration.
  4. Document the host in imperative/<hostname>/README.md.

Script-managed (fallback)

  1. Create imperative/<hostname>/apply.sh following the existing patterns:
    • set -euo pipefail for safety
    • Colored logging helpers (log_info, log_warn, log_error)
    • Idempotent setup.* functions
  2. Document the host in imperative/<hostname>/README.md (system info, components, env vars, usage).
  3. chmod +x imperative/<hostname>/apply.sh.

Then update this README to list the new host.

Script Conventions

Bash scripts in this directory follow these conventions:

  • Strict mode: set -euo pipefail
  • Idempotency: check before mutating, guard re-runs, avoid destructive ops
  • Function naming: setup.* prefix (setup.docker, setup.wireguard, …)
  • Logging: colored log_info / log_warn / log_error helpers
  • Environment variables: documented per-host, fail or warn gracefully when missing
  • Linting: run shellcheck imperative/<hostname>/apply.sh

Integration with NixOS / globals.nix

Even imperative hosts share the repo’s source of truth:

  • WireGuard addressing follows the topology in globals.nix (10.100.0.0/24)
  • Syncthing device IDs are coordinated via globals.nix and accepted on other nodes
  • New keys/IDs generated on first activation should be written back into globals.nix

Transitioning to Full NixOS

When migrating a host to NixOS:

  1. Use the imperative config as a reference for current state
  2. Create systems/<hostname> and test in a VM
  3. Perform the migration, then archive the imperative config

Comparison

Aspect Nix on host (aomi) Bash script (nagoya) Full NixOS (/systems)
Approach Declare via Nix Scripts to reach state Declare desired state
Base OS Any (Fedora, …) Any Linux NixOS only
Idempotency Automatic Manual (careful coding) Automatic
Rollback Per-generation (Nix) Manual/difficult Built-in generations
Reproducibility High Best effort Guaranteed