let # This clan-core pins the zerotier `allowedIps` interface (admit by network # IPv6), but node IDs are the stable per-device handle (what `zerotier-cli # info` prints). Derive a member's IP on THIS network from the controller's # network id so external members can be listed by node id, as below. ztNetworkId = builtins.readFile ./vars/per-machine/control/zerotier/zerotier-network-id/value; ztMemberIp = nodeId: let full = "fd" + ztNetworkId + "9993" + nodeId; h = i: builtins.substring (i * 4) 4 full; in "${h 0}:${h 1}:${h 2}:${h 3}:${h 4}:${h 5}:${h 6}:${h 7}"; in { # Ensure this is unique among all clans you want to use. meta.name = "cnx-network-clan"; meta.domain = "cnx-network.internal"; inventory.machines = { control = { }; ns1 = { }; ns2 = { }; }; inventory.instances = { admin = { roles.default.tags.all = { }; roles.default.settings.allowedKeys = { "berwn" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIENAjhGQGraQoAjJzsomKP8GAmQPeGL1rNRNHgRcLqtT"; "kurogeek" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEcZ/p1Ofa9liwIzPWzNtONhJ7+FUWd2lCz33r81t8+w kurogeek@kurogeek"; }; }; zerotier = { roles.controller.machines."control" = { }; roles.peer.tags.all = { }; # External members admitted by ZeroTier node id (stable per device). # Inventory machines are auto-accepted; this is only for peers outside the # clan. Node id comes from `zerotier-cli info` on the joining device. roles.controller.settings.allowedIps = map ztMemberIp [ "8802c8d7e0" # alex-nixos "2bd36db8cc" # kurogeek-thinkpad ]; }; tor = { roles.server.tags.nixos = { }; }; # Direct SSH to public IPs — clan's priority-1 connection path, with the # ZeroTier mesh and Tor kept as automatic fallbacks. Raw IPs (not the # ns1/ns2 DNS names) so reaching these hosts never depends on their own # DNS being up. internet = { roles.default.machines.control.settings.host = "77.42.68.181"; roles.default.machines.ns1.settings.host = "46.224.170.206"; roles.default.machines.ns2.settings.host = "157.180.70.82"; }; # Recovery root password for console access when a machine fails to boot. emergency-access = { roles.default.tags.nixos = { }; }; # Encrypted, deduplicating backups. control hosts the repos; ns1 is the # only client, backing up its declared clan.core.state (the Knot DNSSEC # keystore) over the mesh. Repo lives at /var/lib/borgbackup/ns1 on control. # Cross-host so an ns1 loss is recoverable; repokey encryption means control # never holds plaintext. Run `clan vars generate ns1` (YubiKey) before deploy. borgbackup = { roles.server.machines.control = { }; roles.client.machines.ns1 = { }; }; }; machines = { }; }