nix: give the gateway, resolver and bridge their own enable
`services.hyperhive.gateway.enable`, `gateway.dns.enable` and `network.enable` replace the `hyperhive.enable` gate on all three. Each defaults to false; the modules that need one assert it with `mkDefault true` from inside the guard their own deployment already carries, and `swarm-required-services.nix` — the module that owns what the swarm-services toggle implies — asserts all three explicitly. hive-c0re asserts all three unconditionally, so an ordinary hive keeps getting them with no opt-in: it is the host's only knowledge that agent containers exist. The resolver moves to its own `hive-gateway/dns.nix` so it can be gated without reindenting the nginx half of the module. Reinstates `network.enable`, dropping its `mkRemovedOptionModule` shim. A config still carrying `network.enable = false` from before the removal now switches the bridge off instead of failing eval. Also deletes a duplicate `centralToggleOff` fixture in nix/module-eval.nix. Two sibling slices added it independently (c5f60fd5,ce3b3d94); the merge was textually clean and left `main` failing to evaluate at all, so this file could not be gated without removing one.
This commit is contained in:
parent
a4e4016214
commit
d8e26a17bb
21 changed files with 249 additions and 75 deletions
|
|
@ -7,7 +7,9 @@
|
|||
# Full vhost map + discovery flow + design rationale in
|
||||
# `docs/networking/gateway.md`. Layout: ./options.nix (option declarations),
|
||||
# ./vhosts.nix (the nginx virtual-host tree), ./error-pages.nix
|
||||
# (styled static pages), ./dnsmasq.nix (resolver + DHCP config).
|
||||
# (styled static pages), ./dns.nix + ./dnsmasq.nix (the resolver, which
|
||||
# has an enable of its own because a host can need hive names to resolve
|
||||
# without serving a vhost).
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
|
|
@ -23,7 +25,6 @@ let
|
|||
swarmServiceDomains = config.services.hyperhive.swarm.serviceDomains;
|
||||
matrixCfg = config.services.hyperhive.swarm.matrix;
|
||||
matrixDeployCfg = config.services.hyperhive.deploy.matrix;
|
||||
networkCfg = config.services.hyperhive.network;
|
||||
|
||||
# Every vhost claiming `default_server`, ours and the operator's
|
||||
# alike. Computed once so the assertion below and the message it
|
||||
|
|
@ -113,9 +114,12 @@ let
|
|||
};
|
||||
in
|
||||
{
|
||||
imports = [ ./options.nix ];
|
||||
imports = [
|
||||
./options.nix
|
||||
./dns.nix
|
||||
];
|
||||
|
||||
config = lib.mkIf config.services.hyperhive.enable {
|
||||
config = lib.mkIf cfg.enable {
|
||||
# Publish the kit. Defined here rather than as an option `default`
|
||||
# so it stays a plain value computed once from resolved cert paths —
|
||||
# `tlsFor` closes over `svcCert`/`svcKey`, which are derived in this
|
||||
|
|
@ -126,13 +130,7 @@ in
|
|||
# is the one unit that can say a service was unreachable rather than
|
||||
# merely quiet. Named even on hives that run no swarm collector: the
|
||||
# option is inert unless one is collecting on this host.
|
||||
#
|
||||
# dnsmasq alongside it for the same reason one level down: a name that
|
||||
# stops resolving presents as every client timing out at once.
|
||||
services.hyperhive.swarm.otel.journaldUnits = [
|
||||
"nginx"
|
||||
"dnsmasq"
|
||||
];
|
||||
services.hyperhive.swarm.otel.journaldUnits = [ "nginx" ];
|
||||
|
||||
assertions = [
|
||||
{
|
||||
|
|
@ -255,32 +253,6 @@ in
|
|||
"f /var/lib/hive-gateway/conf/gateway.htpasswd 0644 hive-core hive-core - -"
|
||||
];
|
||||
|
||||
# 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;
|
||||
|
||||
# ACME (Let's Encrypt) integration. nginx vhosts set
|
||||
# `enableACME = true` via the vhost builder; this provides the
|
||||
# shared ACME config (acceptTerms + email).
|
||||
|
|
@ -423,18 +395,6 @@ in
|
|||
# dir removes the need and the exposure together. Re-adding this line
|
||||
# would restore both.
|
||||
|
||||
# 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
|
||||
;
|
||||
};
|
||||
|
||||
networking.firewall = lib.mkIf cfg.openFirewall {
|
||||
allowedTCPPorts = [
|
||||
cfg.port
|
||||
|
|
|
|||
63
nix/host-modules/hive-gateway/dns.nix
Normal file
63
nix/host-modules/hive-gateway/dns.nix
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# 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;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
# Option declarations for `services.hyperhive.gateway.*`. The gateway
|
||||
# is always run alongside hyperhive (it's the single nginx in front of
|
||||
# every surface and the only thing exposed to the outside); there is
|
||||
# no enable flag. An operator who wants their own reverse proxy in
|
||||
# front points it at the gateway's `port`.
|
||||
# Option declarations for `services.hyperhive.gateway.*`. The gateway is
|
||||
# the single nginx in front of every surface and the only thing exposed
|
||||
# to the outside. An operator who wants their own reverse proxy in front
|
||||
# points it at the gateway's `port`.
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
|
|
@ -22,6 +21,18 @@ in
|
|||
];
|
||||
|
||||
options.services.hyperhive.gateway = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Run the hive's reverse proxy (nginx) on this host.";
|
||||
};
|
||||
|
||||
dns.enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Run the hive's resolver (dnsmasq) on this host.";
|
||||
};
|
||||
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 80;
|
||||
|
|
|
|||
Loading…
Reference in a new issue