# The hive's dnsmasq resolver. Split out of ./default.nix because it has # its own enable: a host can need hive names to resolve without serving a # single vhost. Option declared in ./options.nix, config rendered by # ./dnsmasq.nix. { lib, config, ... }: let cfg = config.services.hyperhive.gateway; networkCfg = config.services.hyperhive.network; hyperhiveDomain = config.services.hyperhive.domain; in { config = lib.mkIf cfg.dns.enable { # dnsmasq is a host service alongside nginx, so it reads the host's # /etc/resolv.conf directly and picks up network changes as they # happen — no copy to keep in sync. services.dnsmasq = import ./dnsmasq.nix { inherit lib cfg networkCfg hyperhiveDomain ; }; # dnsmasq binds the bridge interface and answers with the bridge # address, so the resolver is itself a consumer one layer down. services.hyperhive.network.enable = lib.mkDefault true; # A name that stops resolving presents as every client timing out at # once, so this unit's journal is worth reading swarm-wide. services.hyperhive.swarm.otel.journaldUnits = [ "dnsmasq" ]; # The host asks the hive's own resolver, at the BRIDGE IP. # # Every container inherits a COPY of this host's `/etc/resolv.conf` # at start (`nixos-containers.nix`: `cp --remove-destination`, one # shot, not a bind-mount) — so whatever address is written here is # the address every container will try, in its own netns. # # 🚨 That is why this is the bridge IP and not `127.0.0.1`, and the # distinction is load-bearing rather than stylistic: # # value host host-netns containers bridged containers # 127.0.0.1 ok ok THEIR OWN loopback # bridge IP ok ok ok # # dnsmasq binds both `lo` and the bridge (./dnsmasq.nix), so the # bridge IP is reachable from the host too — it is the only value # correct on both sides of a netns boundary. `resolveLocalQueries` # publishes loopback by default, hence both overrides here; the # flag stays on for its `resolv-file` plumbing, which is what keeps # dnsmasq's own upstreams out of the file we are pointing at it. # # Cost, stated because it is real: the host's DNS now depends on # dnsmasq being up. Every container already did. networking.nameservers = lib.mkForce [ networkCfg.bridgeIp ]; networking.resolvconf.useLocalResolver = lib.mkForce false; }; }