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:
- 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.
- 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)
- Add a
homeConfigurations."<user>@<hostname>"entry inflake.nix. - Add a
hostConfigs.<hostname>output when generated host files are needed. - Create
imperative/<hostname>/bootstrap.shto install Nix, check out the repository, and activate the minimal required configuration. - Document the host in
imperative/<hostname>/README.md.
Script-managed (fallback)
- Create
imperative/<hostname>/apply.shfollowing the existing patterns:set -euo pipefailfor safety- Colored logging helpers (
log_info,log_warn,log_error) - Idempotent
setup.*functions
- Document the host in
imperative/<hostname>/README.md(system info, components, env vars, usage). 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_errorhelpers - 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.nixand 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:
- Use the imperative config as a reference for current state
- Create
systems/<hostname>and test in a VM - 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 |