# Renders `services.hyperhive.gateway.vhosts` into # `services.nginx.virtualHosts`: each declared vhost keeps what its module # wrote and gets the gateway's `listen`, 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; # 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); render = name: declared: let own = removeAttrs declared [ "_module" "certificate" "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 = cfg.lib.listen; 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. ''; } ]; } (lib.mkIf cfg.enable { services.nginx.virtualHosts = lib.mapAttrs render cfg.vhosts; }) ]; }