Skip to content

Clan Integration

Clan is our multi-machine coordination and deployment framework. It orchestrates deployments across NixOS and nix-darwin hosts but does not replace the underlying configuration tools.

Think of clan as “Kubernetes for NixOS”. It coordinates deployment across machines but doesn’t replace the underlying NixOS module system, home-manager, or infrastructure provisioning tools.

Kubernetes orchestrates containers but doesn’t replace Docker. Clan orchestrates NixOS deployments but doesn’t replace NixOS modules.

Clan maintains the registry of machines and their deployment targets via clan.machines.*:

modules/clan/machines.nix
clan.machines = {
stibnite = {
nixpkgs.hostPlatform = "aarch64-darwin";
imports = [ config.flake.modules.darwin."machines/darwin/stibnite" ];
};
cinnabar = {
nixpkgs.hostPlatform = "x86_64-linux";
imports = [ config.flake.modules.nixos."machines/nixos/cinnabar" ];
};
};

The inventory assigns machines to service roles via clan.inventory.*:

modules/clan/inventory/services/zerotier.nix
inventory.instances.zerotier = {
roles.controller.machines."cinnabar" = { };
roles.peer.machines = {
"electrum" = { };
"stibnite" = { };
"blackphos" = { };
};
};

This pattern coordinates multi-machine services. Cinnabar runs as zerotier controller; other machines join as peers.

Clan generates and manages secrets via the vars system using sops encryption under the hood:

  • SSH host keys
  • Zerotier network identities
  • LUKS/ZFS encryption passphrases
  • Service-specific credentials
  • User secrets

Generated via clan vars generate, stored encrypted in vars/ directory.

Clan provides unified deployment commands:

  • clan machines install <machine> - Initial installation (bare metal or VM)
  • clan machines update <machine> - Configuration updates
  • clan vars generate - Generate/regenerate secrets

Clan coordinates services across multiple machines:

# Example: User service with password management
inventory.instances.user-cameron = {
roles.default.machines = {
"cinnabar" = { };
"electrum" = { };
"galena" = { };
};
};

Each service instance can have multiple roles (controller, peer, default, etc.) assigned to different machines.

CapabilityManaged byRelationship to clan
Cloud infrastructure provisioningTerranix/TerraformClan deploys TO infrastructure that terranix creates
User environment configurationHome-ManagerDeployed WITH clan, not BY clan
User-level secrets (legacy)sops-nixSome secrets still in direct sops-nix pending migration to clan vars
NixOS/darwin system configurationNixOS modulesClan imports and deploys configs, doesn’t define them
Nixpkgs overlays and configFlake-levelOutside clan scope entirely

Terranix creates cloud infrastructure; clan deploys to it.

# modules/terranix/hetzner.nix - Creates VMs
resource.hcloud_server.cinnabar = {
name = "cinnabar";
server_type = "cx22";
# ... VM configuration
};
# Provisioner calls clan after VM exists
provisioner.local-exec = {
command = "clan machines install cinnabar";
};

Terranix creates the server, then clan installs NixOS on it. Clan doesn’t provision infrastructure; it consumes infrastructure.

Home-manager configures user environments. Clan deploys the full machine configuration, which includes home-manager.

modules/machines/darwin/stibnite.nix
home-manager.users.crs58 = {
imports = with config.flake.modules.homeManager; [
aggregate-core
aggregate-ai
aggregate-development
];
};

Home-manager configuration is defined OUTSIDE clan, using deferred module composition. When you run clan machines update, home-manager activates as part of system activation. Clan doesn’t know about home-manager specifically.

Some user-level secrets use direct sops-nix configuration alongside clan vars.

modules/home/core/git.nix
sops.secrets."users/crs58/github-signing-key" = {
sopsFile = "${inputs.self}/secrets/users/crs58.sops.yaml";
};

New user secrets use clan vars.

Clan vars is the primary secrets management system for all secrets (system and user). Clan vars uses sops encryption internally and provides unified secret generation, distribution, and management.

The infrastructure uses clan vars as the primary secrets system, with some legacy sops-nix patterns remaining:

Clan vars (primary)

  • Generated by clan vars system
  • Machine-specific and user-specific secrets
  • Examples: SSH host keys, zerotier identities, LUKS passphrases, user credentials
  • Managed via: clan vars generate
  • Storage: vars/ directory, encrypted with sops
machines/nixos/cinnabar/vars/zerotier/...
# Vars are generated automatically
# machines/darwin/stibnite/vars/user-secrets/...

Legacy sops-nix (supplementary)

  • Manually created via sops CLI
  • User-specific secrets in legacy format
  • Examples: Some GitHub tokens, API keys, signing keys, personal credentials
  • Managed via: sops secrets/users/username.sops.yaml
  • Storage: secrets/ directory, encrypted with age
# Secrets manually created and encrypted (legacy)
sops.secrets."users/crs58/github-token" = {
sopsFile = ./secrets/users/crs58.sops.yaml;
};

Clan vars handles both generated secrets (SSH keys, service credentials) and manually-created secrets (API tokens, personal credentials). The distinction is not about secret type but about creation method. New secrets use clan vars; legacy sops-nix patterns remain functional for existing configurations.

Terranix (provisions) → Clan (deploys)
─────────────────────────────────────────────
terraform.hcloud_server → clan machines install
terraform.hcloud_volume → (consumed by NixOS config)

Terranix creates resources, calls clan to deploy NixOS.

Deferred modules (define) → Clan machines (deploy) → Home-Manager (activates)
───────────────────────────────────────────────────────────────────────────────
modules/home/ai/*.nix → clan machines update → home-manager switch
modules/home/shell/*.nix → (part of system config) → (part of activation)

Home-manager modules defined using deferred module composition, deployed via clan.

Clan vars (primary) Legacy sops-nix (supplementary)
─────────────────── ───────────────────────────────
SSH host keys Some GitHub tokens
Zerotier identities Some API keys
LUKS passphrases Some personal credentials
User credentials (new) User credentials (legacy)

Both systems coexist. New secrets use clan vars; legacy sops-nix patterns remain functional.

Current machines managed by clan:

HostnameTypePlatformRoleDeployment
stibniteDarwin laptopaarch64-darwinWorkstationclan machines update
blackphosDarwin laptopaarch64-darwinWorkstationclan machines update
rosegoldDarwin laptopaarch64-darwinWorkstationclan machines update
argentumDarwin laptopaarch64-darwinWorkstationclan machines update
cinnabarNixOS VPSx86_64-linuxZerotier controllerclan machines update
electrumNixOS VPSx86_64-linuxServerclan machines update
galenaNixOS GCPx86_64-linuxCPU computeclan machines update
scheeliteNixOS GCPx86_64-linuxGPU computeclan machines update

”Clan manages infrastructure provisioning”

Section titled “”Clan manages infrastructure provisioning””

Reality: Clan deploys to infrastructure; it doesn’t provision infrastructure. Terranix/terraform creates VMs, networks, DNS records. Clan installs NixOS and deploys configurations to those resources.

Reality: Clan coordinates machine deployments which may include home-manager. Home-manager configurations are defined outside clan using deferred module composition. Clan’s machines update deploys the full machine config including home-manager.

”Clan vars can’t handle user secrets”

Section titled “”Clan vars can’t handle user secrets””

Reality: Clan vars handles all secrets (system and user). The current mix of clan vars and sops-nix reflects historical patterns, not architectural limitation. Clan vars uses sops encryption internally and can manage both generated and manually-created secrets.

Reality: Clan orchestrates deployment of NixOS services across machines. Clan inventory assigns machines to service roles. NixOS modules define the actual service configuration.