From 8f227a1bc505adfaa5c039316cab4d26971dca60 Mon Sep 17 00:00:00 2001 From: arcnmx Date: Thu, 21 Mar 2024 11:25:31 -0700 Subject: [PATCH] feat(nginx): enable option for vhost/location --- modules/nixos/nginx/enable.nix | 47 ++++++++++++++++++++++++ modules/nixos/nginx/listen.nix | 64 ++++++++++++++++++++++++--------- nixos/access/home-assistant.nix | 10 ++++-- nixos/access/plex.nix | 15 ++++---- nixos/access/unifi.nix | 2 +- nixos/access/vouch.nix | 3 +- systems/hakurei/nixos.nix | 6 ++-- 7 files changed, 116 insertions(+), 31 deletions(-) create mode 100644 modules/nixos/nginx/enable.nix diff --git a/modules/nixos/nginx/enable.nix b/modules/nixos/nginx/enable.nix new file mode 100644 index 00000000..611d8e6e --- /dev/null +++ b/modules/nixos/nginx/enable.nix @@ -0,0 +1,47 @@ +{ + lib, + ... +}: let + inherit (lib.options) mkOption mkEnableOption; + inherit (lib.modules) mkIf mkOverride; + mkExtraForce = mkOverride 25; + locationModule = { config, virtualHost, ... }: { + options = with lib.types; { + enable = mkEnableOption "enable location" // { + default = true; + }; + }; + config = mkIf (!virtualHost.enable || !config.enable) { + extraConfig = mkExtraForce "deny all;"; + }; + }; + hostModule = { config, ... }: { + options = with lib.types; { + enable = mkEnableOption "enable server" // { + default = true; + }; + locations = mkOption { + type = attrsOf (submoduleWith { + modules = [ locationModule ]; + shorthandOnlyDefinesConfig = true; + }); + }; + }; + + config = mkIf (!config.enable) { + default = mkExtraForce false; + extraConfig = mkExtraForce '' + deny all; + ''; + }; + }; +in { + options = with lib.types; { + services.nginx.virtualHosts = mkOption { + type = attrsOf (submoduleWith { + modules = [ hostModule ]; + shorthandOnlyDefinesConfig = true; + }); + }; + }; +} diff --git a/modules/nixos/nginx/listen.nix b/modules/nixos/nginx/listen.nix index 8308bd1e..4381a290 100644 --- a/modules/nixos/nginx/listen.nix +++ b/modules/nixos/nginx/listen.nix @@ -4,17 +4,26 @@ ... }: let inherit (lib.options) mkOption mkEnableOption; - inherit (lib.modules) mkIf mkDefault mkOptionDefault mkForce mkOverride; - inherit (lib.attrsets) mapAttrsToList filterAttrs removeAttrs; - inherit (lib.lists) concatMap; + inherit (lib.modules) mkIf mkMerge mkOptionDefault mkForce mkOverride mkRenamedOptionModule; + inherit (lib.attrsets) attrValues mapAttrs mapAttrsToList; + inherit (lib.lists) filter concatMap; mkAlmostOptionDefault = mkOverride 1250; inherit (config.services) nginx; - extraListenAttrs = [ "enable" ]; listenModule = { config, virtualHost, ... }: { options = with lib.types; { enable = mkEnableOption "this port" // { default = true; }; + addr = mkOption { + type = nullOr str; + default = null; + description = "shorthand to override config.addresses"; + }; + addresses = mkOption { + type = listOf str; + description = "applies to all listen addresses unless set"; + defaultText = "virtualHost.listenAddresses'"; + }; ssl = mkOption { type = bool; default = false; @@ -22,23 +31,42 @@ port = mkOption { type = nullOr port; }; + extraParameters = mkOption { + type = listOf str; + default = [ ]; + }; + proxyProtocol = mkOption { + type = bool; + default = false; + }; }; config = { enable = mkIf (config.ssl && !virtualHost.ssl.enable) (mkForce false); - _module.freeformType = with lib.types; attrsOf (oneOf [ - str (listOf str) (nullOr port) bool - ]); port = mkOptionDefault ( if config.ssl then nginx.defaultSSLListenPort else nginx.defaultHTTPListenPort ); + addresses = mkMerge [ + (mkOptionDefault virtualHost.listenAddresses') + (mkIf (config.addr != null) (mkAlmostOptionDefault [ config.addr ])) + ]; }; }; hostModule = { config, ... }: let - cfg = config.listenPorts; - enabledPorts = filterAttrs (_: port: port.enable) cfg; + cfg = attrValues config.listen'; + enabledCfg = filter (port: port.enable) cfg; + mkListen = listen: addr: let + listenAttrs = { + inherit addr; + inherit (listen) port ssl extraParameters proxyProtocol; + }; + in mapAttrs (_: mkAlmostOptionDefault) listenAttrs; + mkListens = listen: map (mkListen listen) listen.addresses; in { + imports = [ + (mkRenamedOptionModule [ "listenPorts" ] [ "listen'" ]) + ]; options = with lib.types; { - listenPorts = mkOption { + listen' = mkOption { type = attrsOf (submoduleWith { modules = [ listenModule ]; specialArgs = { @@ -47,15 +75,19 @@ }); default = { }; }; + listenAddresses' = mkOption { + type = listOf str; + description = "listenAddresses or defaultListenAddresses if empty"; + }; }; config = { - listen = let - addresses = if config.listenAddresses != [ ] then config.listenAddresses else nginx.defaultListenAddresses; - in mkIf (cfg != { }) (mkAlmostOptionDefault ( - concatMap (addr: mapAttrsToList (_: listen: { - addr = mkDefault addr; - } // removeAttrs listen extraListenAttrs) enabledPorts) addresses + enable = mkIf (cfg != [ ] && enabledCfg == [ ]) (mkForce false); + listenAddresses' = mkOptionDefault ( + if config.listenAddresses != [ ] then config.listenAddresses else nginx.defaultListenAddresses + ); + listen = mkIf (cfg != { }) (mkAlmostOptionDefault ( + concatMap (mkListens) enabledCfg )); }; }; diff --git a/nixos/access/home-assistant.nix b/nixos/access/home-assistant.nix index a697c742..3a718054 100644 --- a/nixos/access/home-assistant.nix +++ b/nixos/access/home-assistant.nix @@ -9,12 +9,16 @@ listenPorts = { http = { }; https.ssl = true; - hass = mkIf (!home-assistant.enable) { port = mkDefault home-assistant.config.http.server_port; }; + hass = { + enable = !home-assistant.enable; + port = mkDefault home-assistant.config.http.server_port; + extraParameters = [ "default_server" ]; + }; }; in { config.services.nginx.virtualHosts = { home-assistant = { - inherit name listenPorts; + inherit name; locations."/" = { proxy = { websocket.enable = true; @@ -33,7 +37,7 @@ in { websocket.enable = true; headers.enableRecommended = true; }; - proxyPass = mkIf (!home-assistant.enable) (mkDefault + proxyPass = (mkDefault nginx.virtualHosts.home-assistant.locations."/".proxyPass ); }; diff --git a/nixos/access/plex.nix b/nixos/access/plex.nix index b2a8e5ac..05ce80a7 100644 --- a/nixos/access/plex.nix +++ b/nixos/access/plex.nix @@ -52,17 +52,20 @@ in { in { plex = { inherit name locations extraConfig kTLS; + listenPorts = { + http = { }; + https.ssl = true; + external = { + enable = mkDefault (access.externalPort != null); + port = mkDefault access.externalPort; + extraParameters = [ "default_server" ]; + }; + }; }; plex'local = { inherit name locations extraConfig kTLS; local.enable = true; }; - plex-external = mkIf (access.externalPort != null) { - serverName = mkDefault "plex.${config.networking.domain}"; - default = mkDefault true; - listenPorts.external.port = access.externalPort; - inherit extraConfig locations; - }; }; }; config.networking.firewall.allowedTCPPorts = mkIf (access.externalPort != null) [ diff --git a/nixos/access/unifi.nix b/nixos/access/unifi.nix index e8da84be..9ae67cef 100644 --- a/nixos/access/unifi.nix +++ b/nixos/access/unifi.nix @@ -43,9 +43,9 @@ in { listenPorts.management = { port = access.managementPort; ssl = true; + extraParameters = [ "default_server" ]; }; ssl.force = true; - default = mkDefault true; inherit name locations extraConfig kTLS; }; unifi = { diff --git a/nixos/access/vouch.nix b/nixos/access/vouch.nix index 57959be9..6a7d382a 100644 --- a/nixos/access/vouch.nix +++ b/nixos/access/vouch.nix @@ -71,7 +71,8 @@ in { (localLocations "sso.local.${networking.domain}") ]; }; - vouch'tail = mkIf tailscale.enable { + vouch'tail = { + enable = mkDefault tailscale.enable; name = { inherit (name) shortServer; qualifier = mkDefault "tail"; diff --git a/systems/hakurei/nixos.nix b/systems/hakurei/nixos.nix index 796a5ef5..4df01403 100644 --- a/systems/hakurei/nixos.nix +++ b/systems/hakurei/nixos.nix @@ -106,7 +106,7 @@ in { extraDomainNames = mkMerge [ virtualHosts.vouch.serverAliases virtualHosts.vouch'local.allServerNames - (mkIf tailscale.enable virtualHosts.vouch'tail.allServerNames) + (mkIf virtualHosts.vouch'tail.enable virtualHosts.vouch'tail.allServerNames) ]; }; unifi = { @@ -219,9 +219,7 @@ in { keycloak'local.ssl.cert.name = "keycloak"; vouch.ssl.cert.name = "vouch"; vouch'local.ssl.cert.name = "vouch"; - vouch'tail = mkIf tailscale.enable { - ssl.cert.name = "vouch"; - }; + vouch'tail.ssl.cert.name = "vouch"; unifi = { # we're not the real unifi record-holder, so don't respond globally.. local.denyGlobal = true;