117 lines
4.1 KiB
Nix
117 lines
4.1 KiB
Nix
# Renders `services.hyperhive.gateway.vhosts` into
|
|
# `services.nginx.virtualHosts`: each declared vhost keeps what its module
|
|
# wrote and gets the gateway's `listen` (the private one when it sets
|
|
# `public = false`), the TLS attributes for its name and the security headers.
|
|
#
|
|
# Its own module rather than part of ./default.nix because the
|
|
# "declared while the gateway is off" assertion has to hold when
|
|
# `gateway.enable` is false, where ./default.nix defines nothing.
|
|
{ lib, config, ... }:
|
|
let
|
|
cfg = config.services.hyperhive.gateway;
|
|
listen = import ./listen.nix { inherit lib; };
|
|
|
|
# What the gateway owns on a vhost. A declared vhost naming one of these
|
|
# fails the eval.
|
|
gatewayOwned = [
|
|
"listen"
|
|
"addSSL"
|
|
"onlySSL"
|
|
"enableACME"
|
|
"useACMEHost"
|
|
"sslCertificate"
|
|
"sslCertificateKey"
|
|
];
|
|
|
|
offenders = lib.concatMap (
|
|
name: map (attr: "${name}.${attr}") (lib.filter (a: cfg.vhosts.${name} ? ${a}) gatewayOwned)
|
|
) (lib.attrNames cfg.vhosts);
|
|
|
|
privateOnly = lib.filter (name: !cfg.vhosts.${name}.public) (lib.attrNames cfg.vhosts);
|
|
wildcardPrivate = lib.filter listen.isWildcard cfg.privateListenAddresses;
|
|
|
|
render =
|
|
name: declared:
|
|
let
|
|
own = removeAttrs declared [
|
|
"_module"
|
|
"certificate"
|
|
"public"
|
|
"securityHeaders"
|
|
];
|
|
base =
|
|
if declared.certificate != null then
|
|
{
|
|
sslCertificate = declared.certificate.cert;
|
|
sslCertificateKey = declared.certificate.key;
|
|
}
|
|
else
|
|
cfg.lib.tlsFor name;
|
|
# nixos asserts on a vhost declaring both `addSSL` and `forceSSL`.
|
|
tls = if own.forceSSL or false then removeAttrs base [ "addSSL" ] else base;
|
|
in
|
|
tls
|
|
// own
|
|
// {
|
|
listen = if declared.public then cfg.lib.listen else cfg.lib.privateListen;
|
|
extraConfig =
|
|
lib.optionalString declared.securityHeaders cfg.lib.securityHeaders + (own.extraConfig or "");
|
|
}
|
|
// lib.optionalAttrs (own ? default) {
|
|
# At `mkDefault` priority, so an operator can turn this vhost's
|
|
# `default` off with a plain definition.
|
|
default = lib.mkDefault own.default;
|
|
};
|
|
in
|
|
{
|
|
config = lib.mkMerge [
|
|
{
|
|
assertions = [
|
|
{
|
|
assertion = cfg.enable || cfg.vhosts == { };
|
|
message = ''
|
|
services.hyperhive.gateway.vhosts declares ${lib.concatStringsSep ", " (lib.attrNames cfg.vhosts)}
|
|
while services.hyperhive.gateway.enable is false, so nothing
|
|
would serve them. Enable the gateway, or drop the service that
|
|
declares the vhost.
|
|
'';
|
|
}
|
|
{
|
|
assertion = offenders == [ ];
|
|
message = ''
|
|
services.hyperhive.gateway.vhosts sets attributes the gateway owns:
|
|
${lib.concatStringsSep ", " offenders}
|
|
|
|
The gateway sets the listen set and the TLS attributes of every
|
|
vhost it fronts. Declare only the vhost's own locations and
|
|
options; to serve a certificate the gateway does not pick, set
|
|
`certificate` on the vhost.
|
|
'';
|
|
}
|
|
{
|
|
assertion = privateOnly == [ ] || cfg.privateListenAddresses != [ ];
|
|
message = ''
|
|
services.hyperhive.gateway.vhosts sets `public = false` on
|
|
${lib.concatStringsSep ", " privateOnly}
|
|
while services.hyperhive.gateway.privateListenAddresses is empty,
|
|
so these vhosts would listen nowhere. Set the addresses they
|
|
should answer on, or drop `public = false`.
|
|
'';
|
|
}
|
|
{
|
|
assertion = wildcardPrivate == [ ];
|
|
message = ''
|
|
services.hyperhive.gateway.privateListenAddresses holds
|
|
${lib.concatStringsSep ", " wildcardPrivate}, which is every address
|
|
of the host, not a private one: the vhosts with `public = false`
|
|
would answer on the public address too. List the host's private
|
|
addresses (a WireGuard interface's, say).
|
|
'';
|
|
}
|
|
];
|
|
}
|
|
(lib.mkIf cfg.enable {
|
|
services.nginx.virtualHosts = lib.mapAttrs render cfg.vhosts;
|
|
})
|
|
];
|
|
}
|