diff --git a/lib.nix b/lib.nix index 2afa318f..102b6290 100644 --- a/lib.nix +++ b/lib.nix @@ -8,7 +8,7 @@ inherit (nixlib.strings) splitString toLower; inherit (nixlib.lists) imap0 elemAt findFirst; inherit (nixlib.attrsets) mapAttrs listToAttrs nameValuePair; - inherit (nixlib.strings) hasPrefix hasInfix substring fixedWidthString replaceStrings concatMapStringsSep; + inherit (nixlib.strings) hasPrefix hasInfix removePrefix substring fixedWidthString replaceStrings concatMapStringsSep match toInt; inherit (nixlib.trivial) flip toHexString bitOr; toHexStringLower = v: toLower (toHexString v); @@ -31,6 +31,18 @@ nibble0 + (fixedWidthString 1 "0" (toHexStringLower nibble1)); in "${part0 (part 0)}${part 1}:${part 2}ff:fe${part 3}:${part 4}${part 5}"; + parseUrl = url: let + parts = match ''^([^:]+)://(\[[0-9a-fA-F:]+]|[^/:\[]+)(|:[0-9]+)(|/.*)$'' url; + port' = elemAt parts 2; + in assert parts != null; rec { + inherit url parts; + scheme = elemAt parts 0; + host = elemAt parts 1; + port = if port' != "" then toInt (removePrefix ":" port') else null; + hostport = host + port'; + path = elemAt parts 3; + }; + userIs = group: user: builtins.elem group (user.extraGroups ++ [user.group]); mkWinPath = replaceStrings ["/"] ["\\"]; @@ -51,11 +63,17 @@ mkAlmostOptionDefault = mkOverride overrideAlmostOptionDefault; mkAlmostDefault = mkOverride overrideAlmostDefault; mkAlmostForce = mkOverride overrideAlmostForce; + orderJustBefore = 400; orderBefore = 500; + orderAlmostBefore = 600; orderNone = 1000; - orderAfter = 1500; orderAlmostAfter = 1400; - mkAlmostAfter = mkOrder 1400; + orderAfter = 1500; + orderJustAfter = 1600; + mkJustBefore = mkOrder orderJustBefore; + mkAlmostBefore = mkOrder orderAlmostBefore; + mkAlmostAfter = mkOrder orderAlmostAfter; + mkJustAfter = mkOrder orderJustAfter; mapOverride = priority: mapAttrs (_: mkOverride priority); mapOptionDefaults = mapOverride overrideOptionDefault; mapAlmostOptionDefaults = mapOverride overrideAlmostOptionDefault; @@ -79,13 +97,13 @@ in { lib = { domain = "gensokyo.zone"; inherit treeToModulesOutput userIs - eui64 mkWinPath mkBaseDn mkAddress6 + eui64 parseUrl mkWinPath mkBaseDn mkAddress6 toHexStringLower hexCharToInt mapListToAttrs coalesce - mkAlmostOptionDefault mkAlmostDefault mkAlmostForce mapOverride mapOptionDefaults mapAlmostOptionDefaults mapDefaults + mkAlmostOptionDefault mkAlmostDefault mkAlmostForce mapOverride mapOptionDefaults mapAlmostOptionDefaults mapDefaults overrideOptionDefault overrideAlmostOptionDefault overrideDefault overrideAlmostDefault overrideNone overrideAlmostForce overrideForce overrideVM - orderBefore orderNone orderAfter orderAlmostAfter - mkAlmostAfter; + orderJustBefore orderBefore orderAlmostBefore orderNone orderAfter orderAlmostAfter orderJustAfter + mkJustBefore mkAlmostBefore mkAlmostAfter mkJustAfter; inherit (inputs.arcexprs.lib) unmerged json; }; gensokyo-zone = { diff --git a/modules/nixos/nginx/local.nix b/modules/nixos/nginx/local.nix index 3d344634..19540252 100644 --- a/modules/nixos/nginx/local.nix +++ b/modules/nixos/nginx/local.nix @@ -56,7 +56,7 @@ set ${varPrefix}client 1; } ''; - localModule = {config, ...}: let + localModule = {config, xvars, ...}: let cfg = config.local; in { options.local = with lib.types; { @@ -100,7 +100,7 @@ in mkMerge [ (mkIf cfg.emitDenyGlobal (mkBefore allowDirectives)) (mkIf cfg.emitVars (mkBefore (mkAddrVar "$remote_addr" "$local_"))) - (mkIf cfg.emitVars (mkBefore (mkAddrVar "$x_remote_addr" "$x_local_"))) + (mkIf (cfg.emitVars && config.xvars.enable) (mkBefore (mkAddrVar (xvars.remote_addr.get) "$x_local_"))) ]; }; }; @@ -130,13 +130,7 @@ options = with lib.types; { locations = mkOption { - type = attrsOf (submoduleWith { - modules = [locationModule]; - shorthandOnlyDefinesConfig = true; - specialArgs = { - virtualHost = config; - }; - }); + type = attrsOf (submodule [locationModule]); }; }; @@ -149,13 +143,7 @@ in { options = with lib.types; { services.nginx.virtualHosts = mkOption { - type = attrsOf (submoduleWith { - modules = [hostModule]; - shorthandOnlyDefinesConfig = true; - specialArgs = { - nixosConfig = config; - }; - }); + type = attrsOf (submodule [hostModule]); }; }; } diff --git a/modules/nixos/nginx/proxied.nix b/modules/nixos/nginx/proxied.nix index 942a62c8..405dc615 100644 --- a/modules/nixos/nginx/proxied.nix +++ b/modules/nixos/nginx/proxied.nix @@ -1,57 +1,27 @@ { - config, lib, inputs, ... }: let - inherit (inputs.self.lib.lib) mkAlmostAfter mkAlmostOptionDefault; - inherit (lib.options) mkOption mkEnableOption; - inherit (lib.modules) mkIf mkMerge mkBefore mkDefault mkOptionDefault; - inherit (lib.strings) optionalString splitString match; - inherit (lib.attrsets) attrValues; - inherit (lib.lists) length head /*optional*/ any; - inherit (lib.trivial) mapNullable; - #inherit (config) networking; - inherit (config.services) nginx; - schemeForUrl = url: let - parts = splitString ":" url; - in if length parts == 1 then null else head parts; - pathForUrl = url: let - parts = match ''[^:]+://[^/]+(.*)'' url; - in if parts == null then null else head parts; - hostForUrl = url: let - parts = match ''[^:]+://([^/]+).*'' url; - in if parts == null then null else head parts; - xHeadersDefaults = '' - set $x_scheme $scheme; - set $x_forwarded_for $remote_addr; - set $x_remote_addr $remote_addr; - set $x_forwarded_host $host; - set $x_forwarded_server $host; - set $x_host $host; - set $x_referer $http_referer; - set $x_proxy_host $x_host; - ''; - xHeadersProxied = '' - set $x_forwarded_for $proxy_add_x_forwarded_for; + inherit (inputs.self.lib.lib) mkJustBefore mkAlmostOptionDefault orderJustBefore; + inherit (lib.options) mkOption; + inherit (lib.modules) mkIf mkMerge mkOrder mkDefault mkOptionDefault; + xHeadersProxied = { xvars }: '' + ${xvars.init "forwarded_for" "$proxy_add_x_forwarded_for"} if ($http_x_forwarded_proto) { - set $x_scheme $http_x_forwarded_proto; + ${xvars.init "scheme" "$http_x_forwarded_proto"} } if ($http_x_real_ip) { - set $x_remote_addr $http_x_real_ip; + ${xvars.init "remote_addr" "$http_x_real_ip"} } if ($http_x_forwarded_host) { - set $x_forwarded_host $http_x_forwarded_host; + ${xvars.init "host" "$http_x_forwarded_host"} } if ($http_x_forwarded_server) { - set $x_forwarded_server $http_x_forwarded_server; - } - if ($x_referer ~ "^https?://([^/]*)/(.*)$") { - set $x_referer_host $1; - set $x_referer_path $2; + ${xvars.init "forwarded_server" "$http_x_forwarded_server"} } ''; - locationModule = { config, virtualHost, ... }: let + locationModule = { config, virtualHost, xvars, ... }: let cfg = config.proxied; in { options = with lib.types; { @@ -64,94 +34,30 @@ type = bool; readOnly = true; }; - xvars.enable = mkEnableOption "$x_variables"; - redirectScheme = mkEnableOption "redirect to X-Forwarded-Proto" // { - default = cfg.enabled; - }; - rewriteReferer = mkEnableOption "rewrite Referer header" // { - default = cfg.enabled; - }; - }; - proxy = { - enabled = mkOption { - type = bool; - readOnly = true; - }; - scheme = mkOption { - type = nullOr str; - }; - path = mkOption { - type = nullOr str; - }; - host = mkOption { - type = nullOr str; - }; - headers.enableRecommended = mkOption { - type = enum [ true false "nixpkgs" ]; - }; }; }; config = let emitVars = cfg.enabled && !virtualHost.proxied.enabled; - emitRedirectScheme = config.proxy.enabled && cfg.redirectScheme; - emitRefererRewrite = config.proxy.enabled && cfg.rewriteReferer; - emitHeaders = config.proxy.enabled && config.proxy.headers.enableRecommended == true; in { proxied = { enabled = mkOptionDefault (virtualHost.proxied.enabled || cfg.enable != false); - xvars.enable = mkIf (cfg.enabled || emitRedirectScheme || emitHeaders) true; }; proxy = { - enabled = mkOptionDefault (config.proxyPass != null); - headers.enableRecommended = mkOptionDefault ( - if !virtualHost.recommendedProxySettings then false - else if cfg.enabled then true - else "nixpkgs" - ); - scheme = mkOptionDefault ( - mapNullable schemeForUrl config.proxyPass - ); - path = mkOptionDefault ( - mapNullable pathForUrl config.proxyPass - ); - host = mkOptionDefault ( - mapNullable hostForUrl config.proxyPass - ); + headers = { + enableRecommended = mkIf cfg.enabled (mkAlmostOptionDefault true); + rewriteReferer.enable = mkIf cfg.enabled (mkAlmostOptionDefault true); + }; + redirect.enable = mkIf cfg.enabled (mkAlmostOptionDefault true); }; - recommendedProxySettings = mkMerge [ - (mkAlmostOptionDefault (config.proxy.headers.enableRecommended == "nixpkgs")) - ]; + xvars.enable = mkIf cfg.enabled true; extraConfig = mkMerge [ (mkIf emitVars ( - mkBefore xHeadersProxied + mkJustBefore (xHeadersProxied { inherit xvars; }) )) - (mkIf emitRedirectScheme '' - proxy_redirect ${config.proxy.scheme}://$host/ $x_scheme://$host/; - '') - (mkIf emitRefererRewrite '' - if ($x_referer_host = $host) { - set $x_referer "${config.proxy.scheme}://${config.proxy.host}/$x_referer_path"; - } - '') - (mkIf emitHeaders (mkAlmostAfter '' - if ($x_proxy_host = "") { - set $x_proxy_host $proxy_host; - } - if ($x_proxy_host = "") { - set $x_proxy_host ${config.proxy.host}; - } - proxy_set_header Host $x_proxy_host; - proxy_set_header Referer $x_referer; - proxy_set_header X-Real-IP $x_remote_addr; - proxy_set_header X-Forwarded-For $x_forwarded_for; - proxy_set_header X-Forwarded-Proto $x_scheme; - proxy_set_header X-Forwarded-Host $x_forwarded_host; - proxy_set_header X-Forwarded-Server $x_forwarded_server; - '')) ]; }; }; - hostModule = { config, ... }: let + hostModule = { config, xvars, ... }: let cfg = config.proxied; in { options = with lib.types; { @@ -164,13 +70,6 @@ type = bool; default = cfg.enable != false; }; - xvars.enable = mkEnableOption "$x_variables" // { - default = cfg.enabled; - }; - }; - recommendedProxySettings = mkOption { - type = bool; - default = nginx.recommendedProxySettings; }; locations = mkOption { type = attrsOf (submoduleWith { @@ -181,23 +80,17 @@ }; config = { - proxied = { - xvars.enable = mkIf (any (loc: loc.proxied.xvars.enable) (attrValues config.locations)) true; - }; + xvars.enable = mkIf cfg.enabled true; local.denyGlobal = mkIf (cfg.enable == "cloudflared") (mkDefault true); - extraConfig = mkIf cfg.xvars.enable (mkBefore '' - ${xHeadersDefaults} - ${optionalString cfg.enabled xHeadersProxied} - ''); + extraConfig = mkIf (cfg.enabled && config.xvars.enable) ( + mkOrder (orderJustBefore + 25) (xHeadersProxied { inherit xvars; }) + ); }; }; in { options = with lib.types; { services.nginx.virtualHosts = mkOption { - type = attrsOf (submoduleWith { - modules = [ hostModule ]; - shorthandOnlyDefinesConfig = true; - }); + type = attrsOf (submodule [hostModule]); }; }; } diff --git a/modules/nixos/nginx/proxy.nix b/modules/nixos/nginx/proxy.nix new file mode 100644 index 00000000..07f12323 --- /dev/null +++ b/modules/nixos/nginx/proxy.nix @@ -0,0 +1,214 @@ +let + locationModule = { config, name, virtualHost, xvars, gensokyo-zone, lib, ... }: let + inherit (gensokyo-zone.lib) mkJustBefore mkJustAfter mkAlmostOptionDefault mapOptionDefaults coalesce parseUrl; + inherit (lib.options) mkOption mkEnableOption; + inherit (lib.modules) mkIf mkMerge mkBefore mkOptionDefault; + inherit (lib.attrsets) filterAttrs mapAttrsToList; + inherit (lib.strings) hasPrefix removeSuffix concatStringsSep; + inherit (lib.trivial) mapNullable; + cfg = config.proxy; + in { + options = with lib.types; { + proxy = { + enable = mkEnableOption "proxy"; + enabled = mkOption { + type = bool; + readOnly = true; + }; + url = mkOption { + type = str; + }; + path = mkOption { + type = str; + }; + host = mkOption { + type = nullOr str; + }; + websocket.enable = mkEnableOption "websocket proxy" // { + default = virtualHost.proxy.websocket.enable; + }; + parsed = { + scheme = mkOption { + type = nullOr str; + }; + path = mkOption { + type = nullOr str; + }; + host = mkOption { + type = nullOr str; + }; + hostport = mkOption { + type = nullOr str; + }; + port = mkOption { + type = nullOr int; + }; + }; + headers = { + enableRecommended = mkOption { + type = enum [ true false "nixpkgs" ]; + }; + rewriteReferer.enable = mkEnableOption "rewrite referer host"; + set = mkOption { + type = attrsOf (nullOr str); + }; + }; + redirect = { + enable = mkEnableOption "proxy_redirect"; + fromHost = mkOption { + type = str; + default = xvars.get.host; + example = "xvars.get.proxy_host"; + }; + fromScheme = mkOption { + type = str; + default = xvars.get.scheme; + example = "xvars.get.proxy_scheme"; + }; + }; + }; + }; + config = let + emitHeaders = setHeaders' != { }; + url = parseUrl config.proxyPass; + recommendedHeaders = { + Host = if cfg.host == null then xvars.get.proxy_host else cfg.host; + Referer = xvars.get.referer; + X-Real-IP = xvars.get.remote_addr; + X-Forwarded-For = xvars.get.forwarded_for; + X-Forwarded-Proto = xvars.get.scheme; + X-Forwarded-Host = xvars.get.host; + X-Forwarded-Server = xvars.get.forwarded_server; + }; + initProxyVars = '' + ${xvars.init "proxy_scheme" cfg.parsed.scheme} + ${xvars.init "proxy_host" "$proxy_host"} + if (${xvars.get.proxy_host} = "") { + ${xvars.init "proxy_host" cfg.parsed.hostport} + } + ''; + hostHeader = coalesce [ + cfg.headers.set.Host or null + cfg.host + xvars.get.proxy_host + ]; + rewriteReferer = '' + set $x_set_referer ${xvars.get.referer}; + if (${xvars.get.referer_host} = $host) { + set $x_set_referer ${config.proxy.parsed.scheme}://${hostHeader}${xvars.get.referer_path}; + } + ''; + redirect = '' + proxy_redirect ${cfg.redirect.fromScheme}://${cfg.redirect.fromHost}/ ${xvars.get.scheme}://${xvars.get.host}/; + ''; + setHeaders' = filterAttrs (_: header: header != null) cfg.headers.set; + setHeaders = concatStringsSep "\n" (mapAttrsToList ( + name: value: "proxy_set_header ${name} ${xvars.escapeString value};" + ) setHeaders'); + in { + proxy = { + enabled = mkOptionDefault (config.proxyPass != null); + path = mkIf (hasPrefix "/" name) (mkOptionDefault name); + url = mkIf (virtualHost.proxy.url != null) (mkOptionDefault virtualHost.proxy.url); + headers = { + enableRecommended = mkOptionDefault ( + if cfg.enable && virtualHost.proxy.headers.enableRecommended != false then true + else virtualHost.proxy.headers.enableRecommended + ); + set = mkMerge [ + (mkOptionDefault { }) + (mkIf (cfg.headers.enableRecommended == true) (mapOptionDefaults recommendedHeaders)) + (mkIf (cfg.host != null) { + Host = mkIf (cfg.headers.enableRecommended != "nixpkgs") (mkAlmostOptionDefault cfg.host); + }) + (mkIf cfg.headers.rewriteReferer.enable { + Referer = mkAlmostOptionDefault "$x_set_referer"; + }) + (mkIf cfg.websocket.enable (mapOptionDefaults { + Upgrade = "$http_upgrade"; + Connection = "upgrade"; + })) + ]; + }; + host = mkOptionDefault ( + if virtualHost.proxy.host != null then virtualHost.proxy.host + else if cfg.headers.enableRecommended == false then null + else xvars.get.host + ); + parsed = { + scheme = mkOptionDefault ( + mapNullable (_: url.scheme) config.proxyPass + ); + path = mkOptionDefault ( + mapNullable (_: url.path) config.proxyPass + ); + host = mkOptionDefault ( + mapNullable (_: url.host) config.proxyPass + ); + hostport = mkOptionDefault ( + mapNullable (_: url.hostport) config.proxyPass + ); + port = mkOptionDefault ( + mapNullable (_: url.port) config.proxyPass + ); + }; + }; + proxyPass = mkIf cfg.enable (mkAlmostOptionDefault (removeSuffix "/" cfg.url + cfg.path)); + recommendedProxySettings = mkAlmostOptionDefault (cfg.headers.enableRecommended == "nixpkgs"); + extraConfig = mkMerge [ + (mkIf (cfg.enabled && virtualHost.xvars.enable) (mkJustBefore initProxyVars)) + (mkIf (cfg.enabled && cfg.headers.rewriteReferer.enable) (mkJustBefore rewriteReferer)) + (mkIf (cfg.enabled && cfg.redirect.enable) (mkBefore redirect)) + (mkIf (cfg.enabled && emitHeaders) (mkJustAfter setHeaders)) + ]; + }; + }; + hostModule = { config, nixosConfig, lib, ... }: let + inherit (lib.options) mkOption mkEnableOption; + inherit (lib.modules) mkIf; + inherit (lib.attrsets) attrValues; + inherit (lib.lists) any; + inherit (nixosConfig.services) nginx; + cfg = config.proxy; + in { + options = with lib.types; { + proxy = { + host = mkOption { + type = nullOr str; + default = null; + }; + url = mkOption { + type = nullOr str; + default = null; + }; + websocket.enable = mkEnableOption "websocket proxy"; + headers.enableRecommended = mkOption { + type = enum [ true false "nixpkgs" ]; + default = if nginx.recommendedProxySettings then "nixpkgs" else false; + }; + }; + locations = mkOption { + type = attrsOf (submoduleWith { + modules = [ locationModule ]; + shorthandOnlyDefinesConfig = true; + }); + }; + }; + config = let + needsReferer = loc: loc.proxy.enabled && loc.proxy.headers.rewriteReferer.enable; + in { + xvars.parseReferer = mkIf (any needsReferer (attrValues config.locations)) true; + }; + }; +in { + lib, + ... +}: let + inherit (lib.options) mkOption; +in { + options = with lib.types; { + services.nginx.virtualHosts = mkOption { + type = attrsOf (submodule [hostModule]); + }; + }; +} diff --git a/modules/nixos/nginx/ssl.nix b/modules/nixos/nginx/ssl.nix index d40f7c26..f1113a2a 100644 --- a/modules/nixos/nginx/ssl.nix +++ b/modules/nixos/nginx/ssl.nix @@ -10,9 +10,11 @@ inherit (lib.attrsets) mapAttrsToList; inherit (lib.trivial) warnIf; inherit (config.services) nginx; - forceRedirectConfig = virtualHost: '' - if ($x_scheme = http) { - return ${toString virtualHost.redirectCode} https://$x_forwarded_host$request_uri; + forceRedirectConfig = virtualHost: let + xvars = virtualHost.xvars.lib; + in '' + if (${xvars.get.scheme} = http) { + return ${toString virtualHost.redirectCode} https://${xvars.get.host}$request_uri; } ''; locationModule = { config, virtualHost, ... }: let @@ -23,7 +25,7 @@ force = mkEnableOption "redirect to SSL"; }; config = { - proxied.xvars.enable = mkIf emitForce true; + xvars.enable = mkIf emitForce true; extraConfig = mkIf emitForce (forceRedirectConfig virtualHost); }; }; @@ -119,7 +121,7 @@ sslCertificate = mkIf (cfg.cert.path != null) (mkAlmostOptionDefault cfg.cert.path); sslCertificateKey = mkIf (cfg.cert.keyPath != null) (mkAlmostOptionDefault cfg.cert.keyPath); - proxied.xvars.enable = mkIf emitForce true; + xvars.enable = mkIf emitForce true; extraConfig = mkIf emitForce (forceRedirectConfig config); }; }; diff --git a/modules/nixos/nginx/vouch.nix b/modules/nixos/nginx/vouch.nix index 83e4c74b..bc1f3ec1 100644 --- a/modules/nixos/nginx/vouch.nix +++ b/modules/nixos/nginx/vouch.nix @@ -8,11 +8,11 @@ inherit (lib.options) mkOption mkEnableOption; inherit (lib.modules) mkIf mkMerge mkBefore mkAfter mkOptionDefault; inherit (lib.attrsets) mapAttrsToList; - inherit (lib.strings) toLower replaceStrings; + inherit (lib.strings) toLower replaceStrings removePrefix; inherit (config) networking; inherit (config.services) vouch-proxy nginx tailscale; inherit (nginx) vouch; - locationModule = {config, virtualHost, ...}: { + locationModule = {config, virtualHost, xvars, ...}: { options.vouch = with lib.types; { requireAuth = mkEnableOption "require auth to access this location"; setProxyHeader = mkOption { @@ -33,20 +33,19 @@ (mkBefore virtualHost.vouch.auth.lua.accessLogic) ]; }; - proxied.xvars.enable = mkIf (enableVouchTail || virtualHost.vouch.auth.lua.enable) true; + xvars.enable = mkIf (enableVouchTail || virtualHost.vouch.auth.lua.enable) true; + proxy.headers.set.X-Vouch-User = mkOptionDefault "$auth_resp_x_vouch_user"; extraConfig = assert virtualHost.vouch.enable; mkMerge [ (mkIf (!virtualHost.vouch.requireAuth) virtualHost.vouch.auth.requestDirective) (allowOrigin vouch.url) (allowOrigin vouch.authUrl) (mkIf enableVouchLocal (allowOrigin vouch.localUrl)) - (mkIf enableVouchTail (allowOrigin "$x_scheme://${vouch.tailDomain}")) - (mkIf config.vouch.setProxyHeader '' - proxy_set_header X-Vouch-User $auth_resp_x_vouch_user; - '') + (mkIf enableVouchLocal (allowOrigin "sso.local.${networking.domain}")) + (mkIf enableVouchTail (allowOrigin "${xvars.get.scheme}://${vouch.tailDomain}")) ]; }; }; - hostModule = {config, ...}: let + hostModule = {config, xvars, ...}: let cfg = config.vouch; mkHeaderVar = header: toLower (replaceStrings [ "-" ] [ "_" ] header); mkUpstreamVar = header: "\$upstream_http_${mkHeaderVar header}"; @@ -113,7 +112,7 @@ if ngx.ctx.auth_res ~= nil and ngx.ctx.auth_res.status == ngx.HTTP_UNAUTHORIZED then local vouch_url = ngx.var["vouch_url"] or "${vouch.url}" local query_args = ngx.encode_args { - url = string.format("%s://%s%s", ngx.var.x_scheme, ngx.var.x_forwarded_host, ngx.var.request_uri), + url = string.format("%s://%s%s", ngx.var.${removePrefix "$" xvars.get.scheme}, ngx.var.${removePrefix "$" xvars.get.host}, ngx.var.request_uri), ["X-Vouch-Token"] = ngx.ctx.auth_res.header["X-Vouch-Token"] or "", error = ngx.ctx.auth_res.header["X-Vouch-Error"] or "", -- ["vouch-failcount"] is now a session variable and shouldn't be needed anymore @@ -145,13 +144,13 @@ }; extraConfig = let localVouchUrl = '' - if ($x_forwarded_host ~ "\.local\.${networking.domain}$") { + if (${xvars.get.host} ~ "\.local\.${networking.domain}$") { set $vouch_url ${vouch.localUrl}; } ''; tailVouchUrl = '' - if ($x_forwarded_host ~ "\.tail\.${networking.domain}$") { - set $vouch_url $x_scheme://${vouch.tailDomain}; + if (${xvars.get.host} ~ "\.tail\.${networking.domain}$") { + set $vouch_url ${xvars.get.scheme}://${vouch.tailDomain}; } ''; setVouchUrl = [ @@ -170,33 +169,32 @@ mkBefore "auth_request_set \$${authVar} ${mkUpstreamVar header};" )) cfg.auth.variables )); - proxied.xvars.enable = mkIf cfg.enable true; + xvars.enable = mkIf cfg.enable true; locations = mkIf cfg.enable { "/" = mkIf cfg.requireAuth { vouch.requireAuth = mkAlmostOptionDefault true; }; ${cfg.auth.errorLocation} = mkIf (cfg.auth.errorLocation != null) { - proxied.xvars.enable = true; + xvars.enable = true; extraConfig = '' - return 302 $vouch_url/login?url=$x_scheme://$x_forwarded_host$request_uri&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err; + return 302 $vouch_url/login?url=${xvars.get.scheme}://${xvars.get.host}$request_uri&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err; ''; }; - ${cfg.auth.requestLocation} = { config, ... }: { - proxyPass = "${vouch.proxyOrigin}/validate"; - proxy.headers.enableRecommended = false; - proxied.rewriteReferer = false; - extraConfig = let + ${cfg.auth.requestLocation} = { config, xvars, ... }: { + proxy = { + enable = true; + url = vouch.proxyOrigin; # nginx-proxied vouch must use X-Forwarded-Host, but vanilla vouch requires Host - vouchProxyHost = if vouch.doubleProxy.enable + host = if vouch.doubleProxy.enable then (if cfg.localSso.enable then vouch.doubleProxy.localServerName else vouch.doubleProxy.serverName) - else "$x_forwarded_host"; - in '' - proxy_set_header Host ${vouchProxyHost}; - proxy_set_header X-Forwarded-Host $x_forwarded_host; - proxy_set_header Referer $x_referer; - proxy_set_header X-Forwarded-Proto $x_scheme; + else xvars.get.host; + headers = { + set.Content-Length = ""; + rewriteReferer.enable = false; + }; + }; + extraConfig = '' proxy_pass_request_body off; - proxy_set_header Content-Length ""; ''; }; }; diff --git a/modules/nixos/nginx/websocket.nix b/modules/nixos/nginx/websocket.nix deleted file mode 100644 index 47625a68..00000000 --- a/modules/nixos/nginx/websocket.nix +++ /dev/null @@ -1,30 +0,0 @@ -{lib, ...}: let - inherit (lib.modules) mkIf; - inherit (lib.options) mkOption mkEnableOption; - wsModule = {config, ...}: { - options = with lib.types; { - proxy.websocket.enable = mkEnableOption "websocket proxy"; - }; - config = mkIf config.proxy.websocket.enable { - extraConfig = '' - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - ''; - }; - }; - hostModule = {config, ...}: { - imports = [wsModule]; - - options = with lib.types; { - locations = mkOption { - type = attrsOf (submodule wsModule); - }; - }; - }; -in { - options = with lib.types; { - services.nginx.virtualHosts = mkOption { - type = attrsOf (submodule hostModule); - }; - }; -} diff --git a/modules/nixos/nginx/xvars.nix b/modules/nixos/nginx/xvars.nix new file mode 100644 index 00000000..183dc293 --- /dev/null +++ b/modules/nixos/nginx/xvars.nix @@ -0,0 +1,110 @@ +let + locationModule = { config, virtualHost, lib, ... }: let + inherit (lib.options) mkEnableOption; + cfg = config.xvars; + in { + options.xvars = with lib.types; { + enable = mkEnableOption "$x_variables"; + }; + config = let + in { + }; + }; + hostModule = { config, nixosConfig, gensokyo-zone, xvars, lib, ... }: let + inherit (gensokyo-zone.lib) mkJustBefore; + inherit (lib.options) mkOption mkEnableOption; + inherit (lib.modules) mkIf mkMerge mkOptionDefault; + inherit (lib.strings) concatStringsSep; + inherit (lib.attrsets) attrValues filterAttrs mapAttrs mapAttrsToList; + inherit (lib.lists) any; + cfg = config.xvars; + escapeString = value: if value == "" then ''""'' else value; + in { + options = with lib.types; { + xvars = { + enable = mkEnableOption "$x_variables"; + parseReferer = mkEnableOption "$x_referer_{scheme,host,path}"; + defaults = mkOption { + type = attrsOf (nullOr str); + default = rec { + scheme = "$scheme"; + forwarded_for = remote_addr; + remote_addr = "$remote_addr"; + forwarded_server = host; + host = "$host"; + referer = "$http_referer"; + proxy_host = null; + proxy_scheme = null; + }; + }; + lib = mkOption { + type = attrs; + }; + }; + locations = mkOption { + type = attrsOf (submoduleWith { + modules = [ locationModule ]; + shorthandOnlyDefinesConfig = true; + specialArgs = { + inherit nixosConfig gensokyo-zone xvars; + virtualHost = config; + }; + }); + }; + }; + config = let + defaults = concatStringsSep "\n" (mapAttrsToList ( + name: value: "set $x_${name} ${escapeString value};" + ) (filterAttrs (_: value: value != null) cfg.defaults)); + parseReferer = '' + if (${xvars.get.referer} ~ "^(https?)://([^/]*)(/.*)$") { + ${xvars.init "referer_scheme" "$1"} + ${xvars.init "referer_host" "$2"} + ${xvars.init "referer_path" "$3"} + } + ''; + in { + xvars = { + enable = mkMerge [ + (mkIf (any (loc: loc.xvars.enable) (attrValues config.locations)) true) + (mkIf cfg.parseReferer true) + ]; + defaults = mkIf cfg.parseReferer (mkOptionDefault { + referer_scheme = null; + referer_host = null; + referer_path = null; + }); + lib = { + get = mapAttrs (name: default: if cfg.enable then "$x_${name}" else assert default != null; default) cfg.defaults; + init = name: value: assert cfg.enable && cfg.defaults ? ${name}; "set $x_${name} ${escapeString value};"; + inherit escapeString; + }; + }; + extraConfig = mkMerge [ + (mkIf cfg.enable (mkJustBefore defaults)) + (mkIf (cfg.enable && cfg.parseReferer) (mkJustBefore parseReferer)) + ]; + _module.args.xvars = config.xvars.lib; + }; + }; +in { + config, + lib, + gensokyo-zone, + ... +}: let + inherit (lib.options) mkOption; +in { + options = with lib.types; { + services.nginx.virtualHosts = mkOption { + type = attrsOf (submoduleWith { + modules = [ hostModule ]; + shorthandOnlyDefinesConfig = true; + specialArgs = { + inherit gensokyo-zone; + nixosConfig = config; + }; + }); + }; + }; +} diff --git a/nixos/access/barcodebuddy.nix b/nixos/access/barcodebuddy.nix index 496e5577..23939079 100644 --- a/nixos/access/barcodebuddy.nix +++ b/nixos/access/barcodebuddy.nix @@ -7,9 +7,6 @@ inherit (config.services) barcodebuddy nginx; name.shortServer = mkDefault "bbuddy"; serverName = "@bbuddy_internal"; - extraConfig = '' - set $x_proxy_host ${serverName}; - ''; in { config.services.nginx.virtualHosts = { barcodebuddy'php = mkIf barcodebuddy.enable { @@ -18,35 +15,44 @@ in { local.denyGlobal = true; }; barcodebuddy = { - inherit name extraConfig; + inherit name; vouch = { enable = true; requireAuth = false; }; + proxy = { + url = mkIf barcodebuddy.enable (mkDefault + "http://localhost:${toString nginx.defaultHTTPListenPort}" + ); + host = mkDefault serverName; + }; locations = { "/api/" = { - proxy.headers.enableRecommended = true; - proxyPass = mkDefault "${nginx.virtualHosts.barcodebuddy.locations."/".proxyPass}/api/"; + proxy.enable = true; }; "/" = { - proxy.headers.enableRecommended = true; + proxy.enable = true; vouch.requireAuth = true; - proxyPass = mkIf barcodebuddy.enable (mkDefault - "http://localhost:${toString nginx.defaultHTTPListenPort}" - ); }; }; }; barcodebuddy'local = { - inherit name extraConfig; + inherit name; ssl.cert.copyFromVhost = "barcodebuddy"; local.enable = mkDefault true; - locations."/" = { - proxy.headers.enableRecommended = true; + proxy = { + url = mkDefault nginx.virtualHosts.barcodebuddy.proxy.url; + host = mkDefault nginx.virtualHosts.barcodebuddy.proxy.host; + }; + locations."/" = { config, ... }: { + proxy = { + headers.enableRecommended = true; + redirect = { + enable = true; + fromHost = config.proxy.host; + }; + }; proxyPass = mkDefault nginx.virtualHosts.barcodebuddy.locations."/".proxyPass; - extraConfig = '' - proxy_redirect $x_scheme://${serverName}/ $x_scheme://$x_host/; - ''; }; }; }; diff --git a/nixos/access/freeipa.nix b/nixos/access/freeipa.nix index 5e187c36..d19a1aef 100644 --- a/nixos/access/freeipa.nix +++ b/nixos/access/freeipa.nix @@ -18,31 +18,28 @@ let ssl_verify_client optional_no_ca; ''; locations' = domain: { - "/" = { + "/" = { config, xvars, ... }: { + proxy = { + enable = true; + url = mkDefault access.proxyPass; + host = mkDefault domain; + headers = { + rewriteReferer.enable = true; + set = { + X-SSL-CERT = "$ssl_client_escaped_cert"; + }; + }; + redirect = { + enable = true; + fromHost = config.proxy.host; + fromScheme = xvars.get.proxy_scheme; + }; + }; proxyPass = mkDefault access.proxyPass; recommendedProxySettings = false; extraConfig = '' - proxy_set_header Host ${domain}; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Host $host; - proxy_set_header X-Forwarded-Server $host; - proxy_set_header X-SSL-CERT $ssl_client_escaped_cert; - proxy_redirect https://${domain}/ $scheme://$host/; - proxy_ssl_server_name on; proxy_ssl_name ${domain}; - - set $x_referer $http_referer; - if ($x_referer ~ "^https://([^/]*)/(.*)$") { - set $x_referer_host $1; - set $x_referer_path $2; - } - if ($x_referer_host = $host) { - set $x_referer "https://${domain}/$x_referer_path"; - } - proxy_set_header Referer $x_referer; ''; }; }; diff --git a/nixos/access/freepbx.nix b/nixos/access/freepbx.nix index 54d72024..20084c1e 100644 --- a/nixos/access/freepbx.nix +++ b/nixos/access/freepbx.nix @@ -4,7 +4,7 @@ lib, ... }: let - inherit (lib.modules) mkIf mkDefault; + inherit (lib.modules) mkIf mkMerge mkDefault; inherit (lib.lists) optional; inherit (config.services) nginx; system = access.systemForService "freepbx"; @@ -15,38 +15,50 @@ in { proxyScheme = "https"; url = access.proxyUrlFor { serviceName = "freepbx"; portName = proxyScheme; }; ucpUrl = access.proxyUrlFor { serviceName = "freepbx"; portName = "ucp-ssl"; }; + ucpPath = "/socket.io"; # TODO: ports.asterisk/asterisk-ssl? extraConfig = '' proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; - - set $pbx_scheme $scheme; - if ($http_x_forwarded_proto) { - set $pbx_scheme $http_x_forwarded_proto; - } - proxy_redirect ${proxyScheme}://$host/ $pbx_scheme://$host/; ''; locations = { - "/" = { - proxyPass = mkDefault url; + "/" = { xvars, ... }: { + xvars.enable = true; + proxy = { + enable = true; + redirect = { + enable = true; + fromScheme = xvars.get.proxy_scheme; + }; + }; }; - "/socket.io" = { - proxy.websocket.enable = true; - proxyPass = mkDefault "${ucpUrl}/socket.io"; + ${ucpPath} = { xvars, virtualHost, ... }: { + proxy = { + enable = true; + websocket.enable = true; + }; extraConfig = '' proxy_hide_header Access-Control-Allow-Origin; - add_header Access-Control-Allow-Origin $pbx_scheme://$host; + add_header Access-Control-Allow-Origin ${xvars.get.scheme}://${virtualHost.serverName}; ''; }; }; + allLocations = mkMerge [ + locations + { + ${ucpPath}.proxy.url = mkDefault nginx.virtualHosts.freepbx'ucp.proxy.url; + } + ]; name.shortServer = mkDefault "pbx"; kTLS = mkDefault true; in { freepbx = { vouch.enable = mkDefault true; ssl.force = true; - inherit name locations extraConfig kTLS; + proxy.url = mkDefault url; + locations = allLocations; + inherit name extraConfig kTLS; }; freepbx'ucp = { serverName = mkDefault nginx.virtualHosts.freepbx.serverName; @@ -62,12 +74,14 @@ in { extraParameters = [ "default_server" ]; }; }; - proxy.websocket.enable = true; + proxy = { + url = mkDefault ucpUrl; + websocket.enable = true; + }; vouch.enable = mkDefault true; local.denyGlobal = mkDefault nginx.virtualHosts.freepbx.local.denyGlobal; - locations."/socket.io" = { - inherit (locations."/socket.io") proxy extraConfig; - proxyPass = mkDefault nginx.virtualHosts.freepbx.locations."/socket.io".proxyPass; + locations = { + inherit (locations) "/socket.io"; }; inherit extraConfig kTLS; }; @@ -84,16 +98,9 @@ in { }; }; ssl.cert.copyFromVhost = "freepbx"; + proxy.url = mkDefault nginx.virtualHosts.freepbx.proxy.url; local.enable = true; - locations = { - "/" = { - proxyPass = mkDefault nginx.virtualHosts.freepbx.locations."/".proxyPass; - }; - "/socket.io" = { - inherit (locations."/socket.io") proxy extraConfig; - proxyPass = mkDefault nginx.virtualHosts.freepbx.locations."/socket.io".proxyPass; - }; - }; + locations = allLocations; inherit name extraConfig kTLS; }; }; diff --git a/nixos/access/grocy.nix b/nixos/access/grocy.nix index 8a05fa7f..be0dd0e3 100644 --- a/nixos/access/grocy.nix +++ b/nixos/access/grocy.nix @@ -3,25 +3,24 @@ lib, ... }: let - inherit (lib.modules) mkIf mkMerge mkDefault; - inherit (lib.strings) escapeRegex; + inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault; + inherit (lib.strings) removePrefix escapeRegex; inherit (config.services) grocy nginx; inherit (config) networking; name.shortServer = mkDefault "grocy"; serverName = "@grocy_internal"; serverName'local = "@grocy_internal_local"; extraConfig = '' - set $x_proxy_host ${serverName}; set $grocy_user ""; ''; - location = { + locations."/" = { vouch.setProxyHeader = true; - proxy.headers.enableRecommended = true; - extraConfig = '' - proxy_set_header X-Grocy-User $grocy_user; - ''; + proxy = { + enable = true; + headers.set.X-Grocy-User = mkOptionDefault "$grocy_user"; + }; }; - luaAuthHost = { config, ... }: { + luaAuthHost = { config, xvars, ... }: { vouch.auth.lua = { enable = true; accessRequest = '' @@ -34,7 +33,7 @@ status = ngx.HTTP_OK, header = { }, } - -- elseif ngx.re.match(ngx.var["x_forwarded_host"], [[grocy\.(local|tail)\.${escapeRegex networking.domain}$]]) then + -- elseif ngx.re.match(ngx.var["${removePrefix "$" (xvars.get.host)}"], [[grocy\.(local|tail)\.${escapeRegex networking.domain}$]]) then -- ngx.ctx.auth_res = { -- status = ngx.HTTP_OK, -- header = { }, @@ -54,35 +53,40 @@ in { inherit serverName; }; grocy = mkMerge [ luaAuthHost { - inherit name extraConfig; + inherit name extraConfig locations; vouch.enable = true; - locations."/" = mkMerge [ location { - proxyPass = mkIf (grocy.enable) (mkDefault + proxy = { + url = mkIf grocy.enable (mkDefault "http://localhost:${toString nginx.defaultHTTPListenPort}" ); - } ]; + host = mkDefault serverName; + }; } ]; grocy'local = { inherit name; local.enable = mkDefault true; ssl.cert.copyFromVhost = "grocy"; - locations."/" = { - proxy.headers.enableRecommended = true; - proxyPass = mkDefault "http://localhost:${toString nginx.defaultHTTPListenPort}"; + proxy = { + url = mkDefault "http://localhost:${toString nginx.defaultHTTPListenPort}"; + host = nginx.virtualHosts.grocy'local'int.serverName; + }; + locations."/" = { + proxy.enable = true; }; - extraConfig = '' - set $x_proxy_host ${serverName'local}; - ''; }; grocy'local'int = mkMerge [ luaAuthHost { # internal proxy workaround for http2 lua compat issues serverName = serverName'local; - inherit name extraConfig; + inherit name extraConfig locations; + proxy = { + url = mkDefault nginx.virtualHosts.grocy.proxy.url; + host = mkDefault nginx.virtualHosts.grocy.proxy.host; + }; proxied.enable = true; - vouch.enable = true; - locations."/" = mkMerge [ location { - proxyPass = mkDefault nginx.virtualHosts.grocy.locations."/".proxyPass; - } ]; + vouch = { + enable = true; + localSso.enable = true; + }; } ]; }; }; diff --git a/nixos/access/invidious.nix b/nixos/access/invidious.nix index 7b1cb1ac..53b88674 100644 --- a/nixos/access/invidious.nix +++ b/nixos/access/invidious.nix @@ -22,15 +22,17 @@ in { # Buffering off send to the client as soon as the data is received from invidious. proxy_redirect off; proxy_buffering off; - set $x_proxy_host $x_forwarded_host; ''; - location = { - proxy.websocket.enable = true; - proxy.headers.enableRecommended = true; + location = { xvars, ... }: { + proxy = { + enable = true; + websocket.enable = true; + headers.enableRecommended = true; + }; extraConfig = '' proxy_hide_header content-security-policy; add_header content-security-policy "${contentSecurityPolicy}"; - proxy_cookie_domain ${virtualHosts.invidious.serverName} $x_forwarded_host; + proxy_cookie_domain ${virtualHosts.invidious.serverName} ${xvars.get.host}; ''; }; name.shortServer = mkDefault "yt"; @@ -40,20 +42,22 @@ in { invidious = { # lua can't handle HTTP 2.0 requests, so layer it behind another proxy... inherit name extraConfig kTLS; - locations."/" = { - proxyPass = "http://localhost:${toString config.services.nginx.defaultHTTPListenPort}"; - proxy.headers.enableRecommended = true; + proxy = { + url = mkDefault "http://localhost:${toString config.services.nginx.defaultHTTPListenPort}"; + host = mkDefault virtualHosts.invidious'int.serverName; + }; + locations."/" = { xvars, ... }: { + proxy.enable = true; extraConfig = '' proxy_http_version 1.1; - set $x_proxy_host ${virtualHosts.invidious'int.serverName}; - set $invidious_req_check $x_scheme:$request_uri; + set $invidious_req_check ${xvars.get.scheme}:$request_uri; if ($invidious_req_check = "http:/") { - return ${toString virtualHosts.invidious.redirectCode} https://$x_forwarded_host$request_uri; + return ${toString virtualHosts.invidious.redirectCode} https://${xvars.get.host}$request_uri; } ''; }; }; - invidious'int = { config, ... }: { + invidious'int = { config, xvars, ... }: { serverName = "@invidious_internal"; proxied.enable = true; local.denyGlobal = true; @@ -82,29 +86,31 @@ in { ''; }; }; + proxy = { + host = mkDefault xvars.get.host; + url = mkDefault (if cfg.enable + then "http://localhost:${toString cfg.port}" + else access.proxyUrlFor { serviceName = "invidious"; } + ); + }; locations = { "/" = mkMerge [ location { vouch.requireAuth = true; - proxyPass = mkDefault (if cfg.enable - then "http://localhost:${toString cfg.port}" - else access.proxyUrlFor { serviceName = "invidious"; } - ); } ]; }; inherit extraConfig; }; - invidious'local = { + invidious'local = { xvars, ... }: { local.enable = true; ssl.cert.copyFromVhost = "invidious"; - locations."/" = mkMerge [ - location - { - proxyPass = mkDefault virtualHosts.invidious'int.locations."/".proxyPass; - } - ]; + proxy = { + host = mkDefault xvars.get.host; + url = mkDefault virtualHosts.invidious'int.proxy.url; + }; + locations."/" = location; inherit name extraConfig kTLS; }; }; diff --git a/nixos/access/unifi.nix b/nixos/access/unifi.nix index 27592e81..6a4cf0f6 100644 --- a/nixos/access/unifi.nix +++ b/nixos/access/unifi.nix @@ -6,6 +6,7 @@ }: let inherit (lib.modules) mkDefault; inherit (config.services) nginx; + cfg = config.services.unifi; in { config.services.nginx = { virtualHosts = let @@ -13,24 +14,34 @@ in { proxy_redirect off; proxy_buffering off; ''; + locations = { + "/" = { + proxy.enable = true; + }; + "/wss/" = { + proxy = { + enable = true; + websocket.enable = true; + }; + }; + }; name.shortServer = mkDefault "unifi"; kTLS = mkDefault true; in { unifi = { - inherit name extraConfig kTLS; + inherit name extraConfig kTLS locations; vouch.enable = mkDefault true; ssl.force = mkDefault true; - locations."/" = { - proxyPass = mkDefault (access.proxyUrlFor { serviceName = "unifi"; portName = "management"; }); - }; + proxy.url = mkDefault (if cfg.enable + then "https://localhost:8443" + else access.proxyUrlFor { serviceName = "unifi"; portName = "management"; } + ); }; unifi'local = { - inherit name extraConfig kTLS; + inherit name extraConfig kTLS locations; ssl.cert.copyFromVhost = "unifi"; local.enable = true; - locations."/" = { - proxyPass = mkDefault nginx.virtualHosts.unifi.locations."/".proxyPass; - }; + proxy.url = mkDefault nginx.virtualHosts.unifi.proxy.url; }; }; }; diff --git a/nixos/access/vouch.nix b/nixos/access/vouch.nix index 124fee04..c705b145 100644 --- a/nixos/access/vouch.nix +++ b/nixos/access/vouch.nix @@ -14,52 +14,51 @@ in { locations = { "/" = { ssl.force = true; + proxy.enable = true; extraConfig = '' proxy_redirect default; - set $x_proxy_host $x_forwarded_host; ''; }; "/validate" = {config, virtualHost, ...}: { proxied.enable = true; - proxyPass = mkDefault (virtualHost.locations."/".proxyPass + "/validate"); - proxy.headers.enableRecommended = true; + proxy.enable = true; local.denyGlobal = true; - extraConfig = '' - set $x_proxy_host $x_forwarded_host; - ''; }; }; localLocations = kanidmDomain: mkIf (nginx.vouch.localSso.enable && false) { - "/" = { - proxied.xvars.enable = true; + "/" = { xvars, ... }: { extraConfig = '' - proxy_redirect https://sso.${networking.domain}/ $x_scheme://${kanidmDomain}/; + proxy_redirect https://sso.${networking.domain}/ ${xvars.get.scheme}://${kanidmDomain}/; ''; }; }; name.shortServer = mkDefault "login"; in { - vouch = { - inherit name; + vouch = { xvars, ... }: { + inherit name locations; serverAliases = [ nginx.vouch.doubleProxy.serverName ]; proxied.enable = true; + proxy = { + url = mkDefault ( + access.proxyUrlFor { serviceName = "vouch-proxy"; serviceId = "login"; } + ); + host = mkDefault xvars.get.host; + }; local.denyGlobal = true; - locations = mkMerge [ - locations - { - "/".proxyPass = mkDefault ( - access.proxyUrlFor { serviceName = "vouch-proxy"; serviceId = "login"; } - ); - } - ]; }; - vouch'local = { + vouch'local = { xvars, ... }: { name = { inherit (name) shortServer; includeTailscale = mkDefault false; }; serverAliases = mkIf cfg.enable [ nginx.vouch.doubleProxy.localServerName ]; proxied.enable = true; + proxy = { + url = mkDefault ( + access.proxyUrlFor { serviceName = "vouch-proxy"; serviceId = "login.local"; } + ); + host = mkDefault xvars.get.host; + }; local.enable = true; ssl = { force = true; @@ -67,15 +66,10 @@ in { }; locations = mkMerge [ locations - { - "/".proxyPass = mkDefault ( - access.proxyUrlFor { serviceName = "vouch-proxy"; serviceId = "login.local"; } - ); - } (localLocations "sso.local.${networking.domain}") ]; }; - vouch'tail = { + vouch'tail = { xvars, ... }: { enable = mkDefault (tailscale.enable && !nginx.virtualHosts.vouch'local.name.includeTailscale); ssl.cert.copyFromVhost = "vouch'local"; name = { @@ -83,11 +77,12 @@ in { qualifier = mkDefault "tail"; }; local.enable = true; + proxy = { + url = mkDefault nginx.virtualHosts.vouch'local.locations."/".proxyPass; + host = mkDefault xvars.get.host; + }; locations = mkMerge [ locations - { - "/".proxyPass = mkDefault nginx.virtualHosts.vouch'local.locations."/".proxyPass; - } (localLocations "sso.tail.${networking.domain}") ]; }; diff --git a/nixos/barcodebuddy.nix b/nixos/barcodebuddy.nix index a53b324f..d6297665 100644 --- a/nixos/barcodebuddy.nix +++ b/nixos/barcodebuddy.nix @@ -11,26 +11,25 @@ in { EXTERNAL_GROCY_URL = "https://grocy.${config.networking.domain}"; DISABLE_AUTHENTICATION = true; }; - nginxConfig = mkMerge [ + nginxConfig = let + xvars = nginx.virtualHosts.barcodebuddy'php.xvars.lib; + in mkMerge [ '' include ${config.sops.secrets.barcodebuddy-fastcgi-params.path}; '' (mkIf cfg.reverseProxy.enable (mkAfter '' set $bbuddy_https ""; - if ($x_scheme = https) { + if (${xvars.get.scheme} = https) { set $bbuddy_https 1; } fastcgi_param HTTPS $bbuddy_https if_not_empty; - fastcgi_param REQUEST_SCHEME $x_scheme; - fastcgi_param HTTP_HOST $x_forwarded_host; + fastcgi_param REQUEST_SCHEME ${xvars.get.scheme}; + fastcgi_param HTTP_HOST ${xvars.get.host}; '')) ]; }; config.services.nginx.virtualHosts.barcodebuddy'php = mkIf cfg.enable { - proxied = { - enable = cfg.reverseProxy.enable; - xvars.enable = true; - }; + proxied.enable = cfg.reverseProxy.enable; name.shortServer = mkDefault "bbuddy"; }; config.users.users.barcodebuddy = mkIf cfg.enable { diff --git a/nixos/grocy.nix b/nixos/grocy.nix index df40d0f6..4b485e92 100644 --- a/nixos/grocy.nix +++ b/nixos/grocy.nix @@ -11,58 +11,54 @@ in { currency = mkDefault "CAD"; }; }; - services.nginx = let - extraConfig = mkAfter '' - set $grocy_user guest; - set $grocy_middleware Grocy\Middleware\ReverseProxyAuthMiddleware; - set $grocy_auth_header GENSO_GROCY_USER; - set $grocy_auth_env true; + services.nginx.virtualHosts = { + grocy'php = mkIf cfg.enable ({config, xvars, ...}: let + extraConfig = mkAfter '' + set $grocy_user guest; + set $grocy_middleware Grocy\Middleware\ReverseProxyAuthMiddleware; + set $grocy_auth_header GENSO_GROCY_USER; + set $grocy_auth_env true; - if ($http_grocy_api_key) { - set $grocy_user ""; - } - if ($request_uri ~ "^/api(/.*|)$") { - set $grocy_user ""; - } - if ($http_x_vouch_user ~ "^([^@]+)@.*$") { - set $grocy_user $1; - } - if ($http_x_grocy_user) { - #set $grocy_auth_header X-Grocy-User; - #set $grocy_auth_env false; - set $grocy_user $http_x_grocy_user; - } - if ($grocy_user = "") { - set $grocy_middleware Grocy\Middleware\DefaultAuthMiddleware; - } + if ($http_grocy_api_key) { + set $grocy_user ""; + } + if ($request_uri ~ "^/api(/.*|)$") { + set $grocy_user ""; + } + if ($http_x_vouch_user ~ "^([^@]+)@.*$") { + set $grocy_user $1; + } + if ($http_x_grocy_user) { + #set $grocy_auth_header X-Grocy-User; + #set $grocy_auth_env false; + set $grocy_user $http_x_grocy_user; + } + if ($grocy_user = "") { + set $grocy_middleware Grocy\Middleware\DefaultAuthMiddleware; + } - fastcgi_param GROCY_AUTH_CLASS $grocy_middleware; - fastcgi_param GROCY_REVERSE_PROXY_AUTH_USE_ENV $grocy_auth_env; - fastcgi_param GROCY_REVERSE_PROXY_AUTH_HEADER $grocy_auth_header; - fastcgi_param GENSO_GROCY_USER $grocy_user; + fastcgi_param GROCY_AUTH_CLASS $grocy_middleware; + fastcgi_param GROCY_REVERSE_PROXY_AUTH_USE_ENV $grocy_auth_env; + fastcgi_param GROCY_REVERSE_PROXY_AUTH_HEADER $grocy_auth_header; + fastcgi_param GENSO_GROCY_USER $grocy_user; - set $grocy_https ""; - if ($x_scheme = https) { - set $grocy_https 1; - } - fastcgi_param HTTP_HOST $x_forwarded_host; - fastcgi_param REQUEST_SCHEME $x_scheme; - fastcgi_param HTTPS $grocy_https if_not_empty; - ''; - in { - virtualHosts = { - grocy'php = mkIf cfg.enable ({config, ...}: { - name.shortServer = mkDefault "grocy"; - proxied = { - enable = true; - xvars.enable = true; - }; - local.denyGlobal = true; - locations."~ \\.php$" = { - inherit extraConfig; - }; - }); - }; + set $grocy_https ""; + if (${xvars.get.scheme} = https) { + set $grocy_https 1; + } + fastcgi_param HTTP_HOST ${xvars.get.host}; + fastcgi_param REQUEST_SCHEME ${xvars.get.scheme}; + fastcgi_param HTTPS $grocy_https if_not_empty; + ''; + in { + name.shortServer = mkDefault "grocy"; + proxied.enable = true; + xvars.enable = true; + local.denyGlobal = true; + locations."~ \\.php$" = { + inherit extraConfig; + }; + }); }; users.users.grocy = mkIf cfg.enable { uid = 911; diff --git a/systems/hakurei/nixos.nix b/systems/hakurei/nixos.nix index 20e56980..54694bd3 100644 --- a/systems/hakurei/nixos.nix +++ b/systems/hakurei/nixos.nix @@ -72,7 +72,7 @@ in { services.vouch-proxy = { authUrl = "https://${virtualHosts.keycloak'local.serverName}/realms/${config.networking.domain}"; domain = "login.local.${config.networking.domain}"; - #cookie.domain = "local.${config.networking.domain}"; + settings.cookie.domain = "local.${config.networking.domain}"; }; security.acme.certs = { @@ -257,13 +257,13 @@ in { # not the real grocy record-holder, so don't respond globally.. local.denyGlobal = true; ssl.cert.enable = true; - locations."/".proxyPass = "http://${mkAddress6 (access.getAddressFor "tei" "lan")}"; + proxy.url = "http://${mkAddress6 (access.getAddressFor "tei" "lan")}"; }; barcodebuddy = { # not the real bbuddy record-holder, so don't respond globally.. local.denyGlobal = true; ssl.cert.enable = true; - locations."/".proxyPass = "http://${mkAddress6 (access.getAddressFor "tei" "lan")}"; + proxy.url = "http://${mkAddress6 (access.getAddressFor "tei" "lan")}"; }; freepbx = { ssl.cert.enable = true;