Watch
0
0
Fork
You've already forked hyperhive
0

gateway: service modules declare their vhost under gateway.vhosts

Ten service modules (forge, matrix chat, authelia, grafana, otel, nats,
swarm-ui, victorialogs, victoriametrics, bao UI) wrote
services.nginx.virtualHosts themselves, each applying the gateway's
listen set, per-name TLS attrs and security headers by hand. They now
declare services.hyperhive.gateway.vhosts.<name> with only their own
locations and options; ./declared-vhosts.nix renders it into the nginx
vhost with listen, TLS and headers added.

An eval assertion refuses a declared vhost that sets listen, addSSL,
onlySSL, enableACME, useACMEHost, sslCertificate or sslCertificateKey,
and one declared while the gateway is off. nats' own leaf is the new
`certificate` field. The rendered nginx vhosts are unchanged.
This commit is contained in:
atlas 2026-10-16 10:20:13 +02:00 • committed by mara
commit ddb583cc22
17 changed files with 652 additions and 513 deletions

View file

@ -136,6 +136,61 @@ in
'';
};
vhosts = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule {
# Every other attribute is an nginx vhost option, passed through
# to `services.nginx.virtualHosts.<name>` as written.
freeformType = lib.types.attrsOf lib.types.anything;
options.certificate = lib.mkOption {
type = lib.types.nullOr (
lib.types.submodule {
options = {
cert = lib.mkOption {
type = lib.types.str;
description = "Path of the certificate nginx serves for this name.";
};
key = lib.mkOption {
type = lib.types.str;
description = "Path of the private key for `cert`. A path, never a value.";
};
};
}
);
default = null;
description = ''
A certificate pair to serve instead of the one the gateway
picks for this name (`gateway.lib.tlsFor`). For a name whose
certificate is issued outside the gateway's own leaves.
'';
};
}
);
default = { };
internal = true;
description = ''
The nginx vhosts that sit behind this gateway, by server name. A
service module declares its own — locations, `forceSSL`, extra
config — and the gateway renders it into
`services.nginx.virtualHosts.<name>` with the parts it owns:
- `listen`, the gateway's port pair;
- the TLS attributes for that name (`gateway.lib.tlsFor`, or
`certificate` below), with `addSSL` dropped when the vhost sets
`forceSSL`;
- `securityHeaders`, placed ahead of the vhost's own `extraConfig`.
A vhost that sets `listen`, `addSSL`, `onlySSL`, `enableACME`,
`useACMEHost`, `sslCertificate` or `sslCertificateKey` itself fails
the eval: those are the gateway's, and a service that sets them
can bind a port or present a certificate the rest of the gateway
does not.
A vhost declared while the gateway is off fails the eval too: the
name would otherwise be silently unserved.
'';
};
lib = {
listen = lib.mkOption {
type = lib.types.listOf (lib.types.attrsOf lib.types.raw);
@ -144,11 +199,10 @@ in
description = ''
Read-only: the `listen` set every vhost in front of this
gateway shares (plain http on `port`, TLS on `httpsPort`).
Published so a service module can declare its own vhost
without restating the port pair — a vhost that binds a
different set is reachable on a port the gateway does not
consider its own, which is the kind of drift nobody notices
until one name behaves differently from the rest.
Applied to every vhost declared under `vhosts`, and read by
the gateway's own vhosts, so no vhost binds a different
set — one that did would be reachable on a port the gateway
does not consider its own.
'';
};
@ -163,8 +217,8 @@ in
service's: a swarm service's name can sit outside this hive's
domain, and the hive leaf's role refuses it, so that
vhost must serve the swarm-services leaf while everything else
keeps the hive leaf. A service module calls this instead of
deciding — deciding is how the vhost and the cert stop
keeps the hive leaf. The gateway calls this for every vhost it
fronts — a vhost choosing its own is how the vhost and the cert stop
agreeing.
'';
};