Table of contents
- Adding a Host
- Purpose and boundary
- Prerequisites and safety boundary
- Ordered procedure
- 1. Prepare the host composition
- 2. Register the target with the shared builder
- 3. Include the host in update and trust policy
- 4. Validate the declared target before installation
- Success checks, rollback, and troubleshooting
- Canonical source map
Adding a Host
- Type: Runbook
- Status: Current
- Scope: Engineering a new registered NixOS host target in
nixos-config, before physical or VM provisioning- Canonical sources:
AGENTS.md;flake.nix;scripts/new-host-template.nix;justfiles/hosts.just;lib/auto-update-policy.nix;modules/common/default-config.nix;modules/common/base.nix;modules/common/sops-host.nix;hosts/*/default.nix;potential/nova/default.nix;.sops.yaml; Host Provisioning; Security Baseline- Last verified: Source commit
556df88494686003b1c4f20c8e0b99b5afc16a6e(2026-09-12); source HEADb2831d33132967b4c4fb69e6068b2b05fff8fdffchanges onlyflake.lock. Builder, template, policy, staged Nova, and helpers checked 2026-09-13; no host was registered or provisioned.- Review triggers: New host or channel,
makeNixosSystemchanges, host template, inventory options, auto-update policy, SOPS rules/helpers, Disko layout, Home Manager ownership, or provisioning contract
Purpose and boundary
Create a reviewable NixOS configuration target and specify its consumers,
state, access, and update policy. This page stops at the engineering handoff.
Installing it on a machine is a separate, potentially destructive operation
owned by Host Provisioning. A configuration under
potential/ is staged source, not a flake target or evidence that NixOS is
running on that machine. A registered target can build without ever being
deployed; Host Inventory records that distinction.
New hosts change the fleet-wide validation and security surface. Open a Forgejo issue and use the branch/merge-request lifecycle for the target, with the intended role, hardware or VM platform, first-install plan, data preservation, access path, backup scope, update role, and canary evidence. Follow the Security Baseline for SSH, listeners, secrets, privilege, recovery, and monitoring gates.
Prerequisites and safety boundary
- Choose a unique lowercase target name and confirm the intended target hardware/architecture, Nixpkgs branch, primary user, and whether the host will be a normal auto-update consumer. Do not assume a staged producer configuration is a safe default for a new machine.
- Identify persistent disks, external mounts, encryption, application state,
and what must survive installation. Neither a flake build nor a Git rollback
can recover a disk that Disko reformats. Do not run
just provisionfrom this engineering checklist; use the dedicated runbook with target-identity and layout evidence. - Establish a console/rescue path and an off-host recovery route before the first installation. Plan the temporary provisioning identity and permanent SSH-derived host identity without placing private keys in Git, issues, shell history, or Nix strings.
Ordered procedure
1. Prepare the host composition
just add-host HOSTNAME creates and stages hosts/HOSTNAME/default.nix from
scripts/new-host-template.nix. The template is desktop-oriented and sets
role = "unspecified"; it is a scaffold, not an accepted fleet profile.
It does not register the target in flake.nix, generate hardware facts, or
write a reviewed Disko layout. You may instead keep an unfinished composition
under potential/HOSTNAME/, where it is intentionally outside normal host
builds, and promote it only after review.
In the entry module, choose the actual common/server/desktop profile imports,
system user, networking, services, hardware modules, and disko.nix. Set
networking.hostName and the nixosConfig.host inventory fields: role,
purpose, optional fixed location, filterable tags, and gpu.vendors
when relevant. modules/common/default-config.nix supplies defaults for
primaryUser, userEmail, flakeRepo, and sshKeyPath; override them only
for an actual different user or location. If primaryUser changes, ensure
the corresponding home/users/<primaryUser>/ entry point exists, because
flake.nix imports it for every registered host.
Choose system.stateVersion for the first NixOS installation and preserve it
across routine upgrades. Do not copy another host's value without reviewing
the target's intended initial release and state compatibility. Treat host
hardware facts and disk layout as separate reviewed files; the Host
Provisioning runbook covers capture and destructive
layout validation.
2. Register the target with the shared builder
Add the host to flake.nix under nixosConfigurations. For a normal
unstable target the current shape is:
newhost = makeNixosSystem {
configName = "newhost";
};
newhost is an illustrative name; replace both occurrences with the chosen
target. For a deliberately stable target, follow the current Cosmos/Chaos
shape with pkgs = nixpkgs-stable; and
hmFlake = home-manager-stable; in the same builder call. Do not copy the
old inline nixpkgs.lib.nixosSystem example printed by just add-host;
Forgejo issue #224
tracks that output. The shared builder already adds SOPS, Home Manager,
Paseo, the standalone auto-update module, configuration revision, and cache
settings. Do not duplicate those imports in the host.
Before promoting potential/nova, reconcile it against this builder and
current host contract. Its staged default.nix still imports the updater
directly and does not declare nixosConfig.host metadata. Without an explicit
server role, the shared builder would pass isServer = false to Home Manager.
Its producer role,
network exposure, hardware, data, and disk plan require their own review.
This is a source audit finding, not a claim about Nova's live OS or approval
to install it.
3. Include the host in update and trust policy
Review every group in lib/auto-update-policy.nix whose input the new host
actually consumes, including transitive common, profile, Home Manager, and
hardware inputs. Add the host to the correct group hosts lists; do not add
it blindly to every group or leave a shared input without the new consumer.
The update producer uses those lists to select validation builds. Set the
host's nixosConfig.autoUpdate.role deliberately; all currently registered
hosts are consumers, whereas the staged Nova file declares producer intent.
Changing producer topology is a separate control-plane review, not a side
effect of registration.
Map only the secrets the host will consume. During first install, the
provisioning age recipient must cover those encrypted files; after first
boot, the host SSH public key can become the permanent age recipient in the
relevant explicit .sops.yaml rules. Recipient scope is per file/service,
not “all fleet secrets.” Until issue
#224 is fixed, do not
accept just add-secret or just add-secret-remote output as a complete or
safe rule review. Follow Host Provisioning and Secret
Editing and Recipient Rotation
for the staged identity transition. Never commit a private provisioning or
SSH key.
4. Validate the declared target before installation
Stage every new .nix file before flake evaluation; Git-backed flakes do not
see untracked files. From the source checkout, run the non-activating gates:
just check
nix build .#nixosConfigurations.newhost.config.system.build.toplevel --no-link
just inventory newhost
Replace newhost with the registered name. The build checks that the target
closure can be constructed; just inventory prints evaluated role, GPU,
location, tags, and purpose. Neither proves disk safety or deployment. Review
errors against the exact channel, architecture, imports, Home Manager user
path, SOPS keys, and option assertions. Check required MR/CI results and
publish the reviewed revision before provisioning from it.
When the target is ready, the operational Host
Provisioning runbook owns hardware capture, stable
disk-identity comparison, nixos-anywhere, first boot, permanent SOPS key,
bootstrap-key removal, restore, and first verified backup. For a remote test
after installation, create an auto-update hold first and use Safe Testing
and Deployment. Record a genuine deployment
and no-op follow-up for a multi-host or update-control change before closing
the issue.
Success checks, rollback, and troubleshooting
- The host appears exactly once in
nixosConfigurations, uses the intended unstable or stable builder inputs, and has a complete host entry, hardware facts, Disko plan, user, metadata, and deliberate update role. lib/auto-update-policy.nixnames it for the root inputs it really consumes; secret recipient rules name only required files and independent recovery identities. Security and provisioning gates are recorded.just check, the target build, inventory evaluation, and required MR checks pass. That is ready for reviewed provisioning, not “deployed.”- If the target is missing from inventory, check
flake.nixregistration; if an import is missing, check Git staging and relative paths; if Home Manager evaluation fails, check the selected primary-user directory and stable/unstable pairing. Correct the source and rebuild before proceeding. - Before installation, rollback is a reviewed revert/removal of the new target and policy changes. After Disko begins, recovery means restoring a tested backup and reprovisioning; a prior NixOS generation cannot recreate formatted data. Use the operational runbook, not an improvised retry.
Canonical source map
| Concern | Source |
|---|---|
| Registration, shared modules, channel pairing, Home Manager path | flake.nix |
| Host scaffold and helper limitations | scripts/new-host-template.nix, justfiles/hosts.just, issue #224 |
| Inventory fields and current host examples | modules/common/default-config.nix, hosts/*/default.nix |
| Input-to-host validation scope | lib/auto-update-policy.nix |
| Host SOPS identity and recipient policy | modules/common/sops-host.nix, .sops.yaml, Secret Editing and Recipient Rotation |
| Disk, first boot, key transition, backup | Host Provisioning |