{ lib, config, ... }: let dataDir = "/var/lib/acme"; httpPort = 80; httpsPort = 443; in { options.host.reverse_proxy = { enable = lib.mkEnableOption "turn on the reverse proxy"; hostname = lib.mkOption { type = lib.types.str; description = "what host name are we going to be proxying from"; }; forceSSL = lib.mkOption { type = lib.types.bool; description = "force connections to use https"; default = config.host.reverse_proxy.enableACME; }; enableACME = lib.mkOption { type = lib.types.bool; description = "auto renew certificates"; default = true; }; subdomains = lib.mkOption { type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { options = { subdomain = lib.mkOption { type = lib.types.str; description = "what is the default subdomain to be used for this application to be used for"; default = name; }; extraSubdomains = lib.mkOption { type = lib.types.listOf lib.types.str; description = "extra domains that should be configured for this domain"; default = []; }; target = lib.mkOption { type = lib.types.str; description = "what url will all traffic to this application be forwarded to"; }; websockets.enable = lib.mkEnableOption "should the default config proxy websockets"; forwardHeaders.enable = lib.mkEnableOption "should the default config contain forward headers"; extraConfig = lib.mkOption { type = lib.types.lines; default = ""; description = '' These lines go to the end of the upstream verbatim. ''; }; }; })); }; }; config = lib.mkIf config.host.reverse_proxy.enable (lib.mkMerge [ { security.acme = lib.mkIf config.host.reverse_proxy.enableACME { acceptTerms = true; defaults.email = "jan-leila@protonmail.com"; }; services.nginx = { enable = true; virtualHosts = lib.mkMerge ( lib.lists.flatten ( lib.attrsets.mapAttrsToList ( name: value: let hostConfig = { forceSSL = config.host.reverse_proxy.forceSSL; enableACME = config.host.reverse_proxy.enableACME; locations = { "/" = { proxyPass = value.target; proxyWebsockets = value.websockets.enable; recommendedProxySettings = value.forwardHeaders.enable; extraConfig = value.extraConfig; }; }; }; in ( [ { ${"${value.subdomain}.${config.host.reverse_proxy.hostname}"} = hostConfig; } ] ++ builtins.map (subdomain: {${"${subdomain}.${config.host.reverse_proxy.hostname}"} = hostConfig;}) value.extraSubdomains ) ) config.host.reverse_proxy.subdomains ) ); }; networking.firewall.allowedTCPPorts = [ httpPort httpsPort ]; } (lib.mkIf config.host.impermanence.enable { # TODO: figure out how to write an assertion for this # assertions = [ # { # assertion = security.acme.certs..directory == dataDir; # message = "postgres data directory does not match persistence"; # } # ]; environment.persistence."/persist/system/root" = { enable = true; hideMounts = true; directories = [ { directory = dataDir; user = "acme"; group = "acme"; } ]; }; }) ]); }