diff --git a/nix/host-modules/hive-snapshot-store.nix b/nix/host-modules/hive-snapshot-store.nix index fa149656..2a31c5f8 100644 --- a/nix/host-modules/hive-snapshot-store.nix +++ b/nix/host-modules/hive-snapshot-store.nix @@ -191,6 +191,22 @@ in # creates its own tree lazily. systemd.tmpfiles.rules = [ "d ${cfg.path} 0700 root root -" ]; + # Open the receiver's port, scoped to the mesh interface. + # + # ⚠️ Binding the socket to the mesh address is NOT sufficient on its + # own: NixOS's firewall is default-deny and filters in netfilter, + # before a packet ever reaches a bound socket. The bind chooses + # WHICH address accepts connections; it does not open the port. The + # mesh's own UDP port is opened the same explicit way in swarm.nix. + # + # Interface-scoped rather than host-wide so the reachability + # property stays exactly what the option docs claim --- mesh peers + # and nobody else. A global `allowedTCPPorts` would open the port on + # every interface, including whatever public NIC the box has, and + # only the socket's bind address would still be standing between + # the internet and a root `btrfs receive`. + networking.firewall.interfaces.wg-hive.allowedTCPPorts = [ cfg.port ]; + # Socket-activated on purpose: no long-running root daemon, and the # unit exists only while a transfer does. #