diff --git a/deploy/nixos/configuration.nix b/deploy/nixos/configuration.nix index 652de98..6c11db7 100644 --- a/deploy/nixos/configuration.nix +++ b/deploy/nixos/configuration.nix @@ -191,9 +191,29 @@ # activation over an interface that was never set up; a provisioned machine # is unaffected. Guarded on wg0 still being declared so the live image, # which mkForce's the interfaces away, doesn't get a unit with no ExecStart. - systemd.services = lib.mkIf (config.networking.wireguard.interfaces ? wg0) { - wireguard-wg0.unitConfig.ConditionPathExists = "/var/lib/wireguard/wg0.key"; - }; + systemd.services = lib.mkIf (config.networking.wireguard.interfaces ? wg0) ( + let + iface = config.networking.wireguard.interfaces.wg0; + guard = { unitConfig.ConditionPathExists = "/var/lib/wireguard/wg0.key"; }; + # The module emits one unit per peer alongside the interface unit, and a + # skipped interface is NOT a failed dependency, so the peer units still + # run and die on "Unable to modify interface: No such device" — same + # exit 4, different unit. Guard them too. Names come from the module's + # own `peers.*.name` option (whose default is the escaped public key) + # rather than re-deriving the escaping here; the `-refresh` suffix + # follows nixpkgs' peerUnitServiceName, where a peer's null refresh + # interval falls back to the interface's. + refreshes = peer: + (if peer.dynamicEndpointRefreshSeconds != null then + peer.dynamicEndpointRefreshSeconds + else + iface.dynamicEndpointRefreshSeconds) != 0; + peerUnit = peer: + "wireguard-wg0-peer-${peer.name}" + lib.optionalString (refreshes peer) "-refresh"; + in + { wireguard-wg0 = guard; } + // lib.listToAttrs (map (peer: lib.nameValuePair (peerUnit peer) guard) iface.peers) + ); # In-place rename migration: lamassu user → bitspire user. # Runs after `users` activation so the bitspire user exists with its UID.