Per mara: a general fix, not one name in one container. Every container inherits a COPY of the host's /etc/resolv.conf at start (nixos-containers.nix: cp --remove-destination, one shot, not a bind-mount), so the address written there is the address every container tries - in its own netns. That makes the value load-bearing: value host host-netns containers bridged containers 127.0.0.1 ok ok THEIR OWN loopback bridge IP ok ok ok dnsmasq binds lo and the bridge, so the bridge IP works for the host too. It is the only value correct on both sides of a netns boundary. resolveLocalQueries goes ON for its plumbing, not its address: it points dnsmasq's own upstreams at a separate resolv-file, without which dnsmasq reads /etc/resolv.conf and every non-hive query loops the moment the host is pointed at dnsmasq. Its two loopback-publishing effects (networking.nameservers and resolvconf.useLocalResolver) are overridden. Cost: the host's DNS now depends on dnsmasq being up. Every container already did. The forge container keeps its hosts entry from the previous commit - not redundancy, a fallback in a different failure domain: it works with no DNS at all, so SSO does not ride on a host-wide resolver change.
98 lines
4.7 KiB
Nix
98 lines
4.7 KiB
Nix
# Hive-internal DNS resolver + DHCP, running on the host alongside the
|
|
# gateway's nginx — single front-door for both DNS and HTTP, and no
|
|
# container of its own. Listens on the bridge interface from
|
|
# `services.hyperhive.network`; authoritative for the hive domain +
|
|
# sub-domains, forwards everything else upstream. Returns the
|
|
# `services.dnsmasq` value (see ./default.nix); the DHCP pool bounds
|
|
# are computed by hive-network.
|
|
{
|
|
lib,
|
|
networkCfg,
|
|
forgeCfg,
|
|
matrixCfg,
|
|
autheliaCfg,
|
|
uiCfg,
|
|
hyperhiveDomain,
|
|
}:
|
|
{
|
|
enable = true;
|
|
# ON for its *plumbing*, not for the address it publishes.
|
|
#
|
|
# This flag does two separable things upstream. The one that matters
|
|
# here: it points dnsmasq's own upstream servers at a SEPARATE file
|
|
# (`resolv-file = /etc/dnsmasq-resolv.conf`, kept current by
|
|
# resolvconf). Without that, dnsmasq reads `/etc/resolv.conf` for its
|
|
# upstreams — so the moment the host's resolver is pointed at dnsmasq,
|
|
# every non-hive query goes in a circle.
|
|
#
|
|
# The other thing it does is publish `127.0.0.1` as the host's
|
|
# nameserver, which is the wrong address for this hive: see the
|
|
# `nameservers` override in ./default.nix, where the reason lives.
|
|
resolveLocalQueries = true;
|
|
settings = {
|
|
# Bind only on the bridge interface (and lo for health-checks).
|
|
# Outside hosts can't even see the listener.
|
|
interface = [
|
|
networkCfg.bridgeName
|
|
"lo"
|
|
];
|
|
bind-interfaces = true;
|
|
port = 53;
|
|
# Authoritative for the hive domain via the `address` rules below —
|
|
# must not fall back to the host's /etc/hosts. dnsmasq reads
|
|
# /etc/hosts by default, and `gateway.localHostsEntry` populates it
|
|
# with 127.0.0.1 for every hive name (host-side dev convenience,
|
|
# see default.nix). Since moving dnsmasq onto the host, that
|
|
# file is now the *same* /etc/hosts dnsmasq reads for agent queries
|
|
# — its entries win over `address=`, so every agent resolves the
|
|
# hive's own domains back to itself (127.0.0.1 in its own netns)
|
|
# instead of the bridge IP, and can't reach the forge, matrix, or
|
|
# dashboard at all. `no-hosts = true` keeps the authoritative
|
|
# `address=` rules in charge for containers while leaving
|
|
# `networking.hosts` (the actual /etc/hosts entries) untouched for
|
|
# host-side browsing.
|
|
no-hosts = true;
|
|
# Hive authoritative records — answer queries for the hive domain
|
|
# + its sub-domains with the bridge IP, where nginx is reachable
|
|
# from every container netns.
|
|
#
|
|
# The forge / matrix entries are redundant in the common case
|
|
# where `forge.domain` / `matrix.gatewayHost` are sub-domains of
|
|
# `hyperhive.domain` — dnsmasq's `/<domain>/` rule already matches
|
|
# sub-domains. Kept explicit because operators can override either
|
|
# to a cross-domain hostname (e.g. `forge.domain =
|
|
# "git.example.com"`); listing them explicitly keeps that case
|
|
# routed without needing an extra config block.
|
|
address = [
|
|
"/${hyperhiveDomain}/${networkCfg.bridgeIp}"
|
|
]
|
|
++ lib.optional ((forgeCfg.behindGateway or false)) "/${forgeCfg.domain}/${networkCfg.bridgeIp}"
|
|
++ lib.optional (
|
|
matrixCfg.enable && matrixCfg.gatewayHost != null
|
|
) "/${matrixCfg.gatewayHost}/${networkCfg.bridgeIp}"
|
|
++ lib.optional autheliaCfg.enable "/${autheliaCfg.domain}/${networkCfg.bridgeIp}"
|
|
# The swarm UI's name is the swarm APEX by default — a sibling of
|
|
# the three above, not a child of anything this resolver already
|
|
# answers for, so the `/<hive domain>/` rule does not cover it.
|
|
#
|
|
# Published to agents deliberately (mara: publishing it is fine).
|
|
# Reachability is not the access control here: the vhost's
|
|
# `auth_request` + authelia's `group:operators` rule are, and an
|
|
# agent that resolves the name still cannot open the page.
|
|
++ lib.optional uiCfg.enable "/${uiCfg.domain}/${networkCfg.bridgeIp}";
|
|
# DHCP pool covering all usable host addresses on the bridge
|
|
# subnet — bounds computed by hive-network.nix from
|
|
# bridgeIp/bridgePrefixLength. All containers (agents and service
|
|
# containers such as hive-ci) receive their IPs dynamically.
|
|
dhcp-range = "${networkCfg.dhcpRangeStart},${networkCfg.dhcpRangeEnd},1h";
|
|
dhcp-leasefile = "/var/lib/dnsmasq/dnsmasq.leases";
|
|
# No explicit upstream: non-hive queries follow dnsmasq's
|
|
# resolv.conf default — the host's own `/etc/resolv.conf`, so the
|
|
# hive always uses the host's resolvers and follows them live with
|
|
# no copy to go stale. Deliberately no fallback
|
|
# `server=`: dnsmasq queries
|
|
# all known upstreams in parallel, so a hardcoded public resolver
|
|
# would take a share of *normal* traffic, not just fill in when the
|
|
# host file is empty.
|
|
};
|
|
}
|