refactor(nginx): upstream host option

This commit is contained in:
arcnmx 2024-04-27 11:44:58 -07:00
parent b1676079ef
commit c2c8cadc2e
5 changed files with 45 additions and 28 deletions

View file

@ -51,6 +51,7 @@ let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkBefore mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkBefore mkOptionDefault;
inherit (lib.attrsets) filterAttrs mapAttrsToList; inherit (lib.attrsets) filterAttrs mapAttrsToList;
inherit (lib.lists) optional;
inherit (lib.strings) hasPrefix removeSuffix optionalString concatStringsSep; inherit (lib.strings) hasPrefix removeSuffix optionalString concatStringsSep;
inherit (lib.trivial) mapNullable; inherit (lib.trivial) mapNullable;
inherit (nixosConfig.services) nginx; inherit (nixosConfig.services) nginx;
@ -125,7 +126,8 @@ let
upstream = nginx.upstreams'.${cfg.upstream}; upstream = nginx.upstreams'.${cfg.upstream};
upstreamServer = upstream.servers.${upstream.defaultServerName}; upstreamServer = upstream.servers.${upstream.defaultServerName};
dynamicUpstream = hasPrefix "$" cfg.upstream; dynamicUpstream = hasPrefix "$" cfg.upstream;
hasUpstream = cfg.upstream != null && !dynamicUpstream && upstream.defaultServerName != null; hasUpstream = cfg.upstream != null && !dynamicUpstream;
hasUpstreamServer = upstream.defaultServerName != null;
recommendedHeaders = { recommendedHeaders = {
Host = if cfg.host == null then xvars.get.proxy_hostport else cfg.host; Host = if cfg.host == null then xvars.get.proxy_hostport else cfg.host;
Referer = xvars.get.referer; Referer = xvars.get.referer;
@ -139,6 +141,7 @@ let
http = 80; http = 80;
https = 443; https = 443;
}.${cfg.parsed.scheme} or (throw "unsupported proxy_scheme ${toString cfg.parsed.scheme}"); }.${cfg.parsed.scheme} or (throw "unsupported proxy_scheme ${toString cfg.parsed.scheme}");
upstreamHost = coalesce ([ upstream.host ] ++ optional hasUpstreamServer upstreamServer.addr);
port = coalesce [ cfg.parsed.port schemePort ]; port = coalesce [ cfg.parsed.port schemePort ];
hostport = cfg.parsed.host + optionalString (port != schemePort) ":${toString port}"; hostport = cfg.parsed.host + optionalString (port != schemePort) ":${toString port}";
initProxyVars = let initProxyVars = let
@ -239,11 +242,11 @@ let
mapNullable (_: url.path) config.proxyPass mapNullable (_: url.path) config.proxyPass
); );
host = mkOptionDefault ( host = mkOptionDefault (
if hasUpstream then assert url.host == upstream.name; upstreamServer.addr if hasUpstream then assert url.host == upstream.name; upstreamHost
else mapNullable (_: url.host) config.proxyPass else mapNullable (_: url.host) config.proxyPass
); );
port = mkOptionDefault ( port = mkOptionDefault (
if hasUpstream && url.port == null then assert url.host == upstream.name; upstreamServer.port if hasUpstream && hasUpstreamServer && url.port == null then assert url.host == upstream.name; upstreamServer.port
else mapNullable (_: url.port) config.proxyPass else mapNullable (_: url.port) config.proxyPass
); );
}; };

View file

@ -149,6 +149,10 @@ let
servers = mkOption { servers = mkOption {
type = attrsOf upstreamServer; type = attrsOf upstreamServer;
}; };
host = mkOption {
type = nullOr str;
default = null;
};
ssl = { ssl = {
enable = mkEnableOption "ssl upstream"; enable = mkEnableOption "ssl upstream";
host = mkOption { host = mkOption {
@ -276,6 +280,7 @@ let
enable = mkAlmostOptionDefault (if hasUpstream then proxyUpstream.ssl.enable else false); enable = mkAlmostOptionDefault (if hasUpstream then proxyUpstream.ssl.enable else false);
host = mkIf hasUpstream (mkAlmostOptionDefault proxyUpstream.ssl.host); host = mkIf hasUpstream (mkAlmostOptionDefault proxyUpstream.ssl.host);
}; };
host = mkIf (hasUpstream && proxyUpstream.host != null) (mkAlmostOptionDefault proxyUpstream.host);
}; };
}; };
}; };

View file

@ -261,7 +261,7 @@ in {
then "localhost" then "localhost"
else listen; else listen;
in { in {
# TODO: serviceAccess.exportedId = "login"; # TODO: accessService.exportedId = "login";
enable = mkAlmostOptionDefault vouch-proxy.enable; enable = mkAlmostOptionDefault vouch-proxy.enable;
port = mkIf vouch-proxy.enable (mkOptionDefault port); port = mkIf vouch-proxy.enable (mkOptionDefault port);
addr = mkIf vouch-proxy.enable (mkAlmostOptionDefault host); addr = mkIf vouch-proxy.enable (mkAlmostOptionDefault host);

View file

@ -23,7 +23,6 @@ let
proxy = { proxy = {
enable = true; enable = true;
upstream = "freeipa"; upstream = "freeipa";
host = mkDefault config.proxy.ssl.host;
headers = { headers = {
rewriteReferer.enable = true; rewriteReferer.enable = true;
set = { set = {
@ -83,6 +82,7 @@ in {
# TODO: ssl.preread.enable = mkDefault true; # TODO: ssl.preread.enable = mkDefault true;
upstreams'.freeipa = {config, ...}: { upstreams'.freeipa = {config, ...}: {
ssl.host = mkDefault (access.systemFor config.servers.access.accessService.system).access.fqdn; ssl.host = mkDefault (access.systemFor config.servers.access.accessService.system).access.fqdn;
host = mkDefault config.ssl.host;
servers.access = { servers.access = {
accessService = { accessService = {
name = "freeipa"; name = "freeipa";
@ -209,9 +209,10 @@ in {
name.shortServer = mkDefault "idp-ca"; name.shortServer = mkDefault "idp-ca";
locations."/" = mkMerge [ locations."/" = mkMerge [
locations."/" locations."/"
{ ({config, virtualHost, ...}: {
proxy.ssl.host = virtualHosts.freeipa'ca.serverName; proxy.ssl.host = virtualHost.serverName;
} proxy.host = config.proxy.ssl.host;
})
]; ];
ssl = { ssl = {
force = mkDefault virtualHosts.freeipa.ssl.force; force = mkDefault virtualHosts.freeipa.ssl.force;

View file

@ -5,12 +5,14 @@
}: let }: let
inherit (lib.modules) mkIf mkMerge mkBefore mkDefault; inherit (lib.modules) mkIf mkMerge mkBefore mkDefault;
inherit (lib.strings) replaceStrings concatStringsSep concatMapStringsSep escapeRegex; inherit (lib.strings) replaceStrings concatStringsSep concatMapStringsSep escapeRegex;
inherit (config.services.nginx) virtualHosts; inherit (config.services) nginx;
cfg = config.services.invidious; cfg = config.services.invidious;
upstreamName = "invidious'access"; upstreamName = "invidious'access";
upstreamNginx = "invidious'access'nginx";
in { in {
config.services.nginx = { config.services.nginx = {
upstreams'.${upstreamName}.servers = { upstreams' = {
${upstreamName}.servers = {
local = { local = {
enable = mkDefault cfg.enable; enable = mkDefault cfg.enable;
addr = mkDefault "localhost"; addr = mkDefault "localhost";
@ -23,10 +25,19 @@ in {
}; };
}; };
}; };
${upstreamNginx} = {
enable = mkDefault nginx.virtualHosts.invidious'int.enable;
host = mkDefault nginx.virtualHosts.invidious'int.serverName;
servers.local = {
addr = mkDefault "localhost";
port = nginx.defaultHTTPListenPort;
};
};
};
virtualHosts = let virtualHosts = let
invidiousDomains = invidiousDomains =
virtualHosts.invidious.allServerNames nginx.virtualHosts.invidious.allServerNames
++ virtualHosts.invidious'local.allServerNames; ++ nginx.virtualHosts.invidious'local.allServerNames;
contentSecurityPolicy' = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; manifest-src 'self'; media-src 'self' blob: https://*.googlevideo.com:443 https://*.youtube.com:443; child-src 'self' blob:; frame-src 'self'; frame-ancestors 'none'"; contentSecurityPolicy' = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; manifest-src 'self'; media-src 'self' blob: https://*.googlevideo.com:443 https://*.youtube.com:443; child-src 'self' blob:; frame-src 'self'; frame-ancestors 'none'";
contentSecurityPolicy = replaceStrings ["'self'"] ["'self' ${concatStringsSep " " invidiousDomains}"] contentSecurityPolicy'; contentSecurityPolicy = replaceStrings ["'self'"] ["'self' ${concatStringsSep " " invidiousDomains}"] contentSecurityPolicy';
extraConfig = mkBefore '' extraConfig = mkBefore ''
@ -44,26 +55,23 @@ in {
}; };
headers.set.content-security-policy = contentSecurityPolicy; headers.set.content-security-policy = contentSecurityPolicy;
extraConfig = '' extraConfig = ''
proxy_cookie_domain ${virtualHosts.invidious.serverName} ${xvars.get.host}; proxy_cookie_domain ${nginx.virtualHosts.invidious.serverName} ${xvars.get.host};
''; '';
}; };
name.shortServer = mkDefault "yt"; name.shortServer = mkDefault "yt";
localDomains = virtualHosts.invidious'local.allServerNames; localDomains = nginx.virtualHosts.invidious'local.allServerNames;
in { in {
invidious = { invidious = {
# lua can't handle HTTP 2.0 requests, so layer it behind another proxy... # lua can't handle HTTP 2.0 requests, so layer it behind another proxy...
inherit name extraConfig; inherit name extraConfig;
proxy = { proxy.upstream = upstreamNginx;
url = mkDefault "http://localhost:${toString config.services.nginx.defaultHTTPListenPort}"; locations."/" = { xvars, virtualHost, ... }: {
host = mkDefault virtualHosts.invidious'int.serverName;
};
locations."/" = { xvars, ... }: {
proxy.enable = true; proxy.enable = true;
extraConfig = '' extraConfig = ''
proxy_http_version 1.1; proxy_http_version 1.1;
set $invidious_req_check ${xvars.get.scheme}:$request_uri; set $invidious_req_check ${xvars.get.scheme}:$request_uri;
if ($invidious_req_check = "http:/") { if ($invidious_req_check = "http:/") {
return ${toString virtualHosts.invidious.redirectCode} https://${xvars.get.host}$request_uri; return ${toString virtualHost.redirectCode} https://${xvars.get.host}$request_uri;
} }
''; '';
}; };