mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 12:29:19 -08:00
refactor(nginx): headers and proxy vars
This commit is contained in:
parent
692d3aacbd
commit
418caefe64
6 changed files with 154 additions and 37 deletions
76
modules/nixos/nginx/headers.nix
Normal file
76
modules/nixos/nginx/headers.nix
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
let
|
||||||
|
locationModule = { config, virtualHost, xvars, gensokyo-zone, lib, ... }: let
|
||||||
|
inherit (gensokyo-zone.lib) mapOptionDefaults;
|
||||||
|
inherit (lib.options) mkOption;
|
||||||
|
inherit (lib.modules) mkIf mkMerge mkAfter mkOptionDefault;
|
||||||
|
inherit (lib.attrsets) mapAttrsToList;
|
||||||
|
inherit (lib.lists) isList;
|
||||||
|
cfg = config.headers;
|
||||||
|
in {
|
||||||
|
options.headers = with lib.types; {
|
||||||
|
inheritServerDefaults = mkOption {
|
||||||
|
type = bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
set = mkOption {
|
||||||
|
type = attrsOf (nullOr (oneOf [ str (listOf str) ]));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = let
|
||||||
|
mkHeader = name: value:
|
||||||
|
if isList value then mkMerge (map (mkHeader name) value)
|
||||||
|
else mkAfter "add_header ${name} ${xvars.escapeString value};";
|
||||||
|
setHeaders = mapAttrsToList (name: value: mkIf (value != null) (mkHeader name value)) cfg.set;
|
||||||
|
in {
|
||||||
|
headers = {
|
||||||
|
set = mkMerge [
|
||||||
|
(mkOptionDefault { })
|
||||||
|
(mkIf cfg.inheritServerDefaults (mapOptionDefaults virtualHost.headers.set))
|
||||||
|
];
|
||||||
|
};
|
||||||
|
extraConfig = mkMerge setHeaders;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
hostModule = { config, nixosConfig, gensokyo-zone, lib, ... }: let
|
||||||
|
inherit (gensokyo-zone.lib) mapOptionDefaults;
|
||||||
|
inherit (lib.options) mkOption;
|
||||||
|
inherit (nixosConfig.services) nginx;
|
||||||
|
in {
|
||||||
|
options = with lib.types; {
|
||||||
|
headers = {
|
||||||
|
set = mkOption {
|
||||||
|
type = attrsOf (nullOr (oneOf [ str (listOf str) ]));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
locations = mkOption {
|
||||||
|
type = attrsOf (submoduleWith {
|
||||||
|
modules = [ locationModule ];
|
||||||
|
shorthandOnlyDefinesConfig = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
headers = {
|
||||||
|
set = mapOptionDefaults nginx.headers.set;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit (lib.options) mkOption;
|
||||||
|
in {
|
||||||
|
options.services.nginx = with lib.types; {
|
||||||
|
headers = {
|
||||||
|
set = mkOption {
|
||||||
|
type = attrsOf (nullOr (oneOf [ str (listOf str) ]));
|
||||||
|
default = {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
virtualHosts = mkOption {
|
||||||
|
type = attrsOf (submodule [hostModule]);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -68,6 +68,10 @@ let
|
||||||
set = mkOption {
|
set = mkOption {
|
||||||
type = attrsOf (nullOr str);
|
type = attrsOf (nullOr str);
|
||||||
};
|
};
|
||||||
|
hide = mkOption {
|
||||||
|
type = attrsOf bool;
|
||||||
|
default = { };
|
||||||
|
};
|
||||||
};
|
};
|
||||||
redirect = {
|
redirect = {
|
||||||
enable = mkEnableOption "proxy_redirect";
|
enable = mkEnableOption "proxy_redirect";
|
||||||
|
|
@ -103,12 +107,12 @@ let
|
||||||
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}");
|
||||||
port = coalesce [ cfg.parsed.port schemePort ];
|
port = coalesce [ cfg.parsed.port schemePort ];
|
||||||
hostport = cfg.parsed.host + optionalString (port != schemePort) ":${toString cfg.parsed.port}";
|
hostport = cfg.parsed.host + optionalString (port != schemePort) ":${toString port}";
|
||||||
initProxyVars = let
|
initProxyVars = let
|
||||||
initScheme = xvars.init "proxy_scheme" cfg.parsed.scheme;
|
initScheme = xvars.init "proxy_scheme" config.xvars.defaults.proxy_scheme;
|
||||||
initHost = xvars.init "proxy_host" cfg.parsed.host;
|
initHost = xvars.init "proxy_host" config.xvars.defaults.proxy_host;
|
||||||
initPort = xvars.init "proxy_port" port;
|
initPort = xvars.init "proxy_port" config.xvars.defaults.proxy_port;
|
||||||
initHostPort = xvars.init "proxy_hostport" hostport;
|
initHostPort = xvars.init "proxy_hostport" config.xvars.defaults.proxy_hostport;
|
||||||
initUpstream = ''
|
initUpstream = ''
|
||||||
${initScheme}
|
${initScheme}
|
||||||
${initHost}
|
${initHost}
|
||||||
|
|
@ -153,8 +157,17 @@ let
|
||||||
setHeaders = concatStringsSep "\n" (mapAttrsToList (
|
setHeaders = concatStringsSep "\n" (mapAttrsToList (
|
||||||
name: value: "proxy_set_header ${name} ${xvars.escapeString value};"
|
name: value: "proxy_set_header ${name} ${xvars.escapeString value};"
|
||||||
) setHeaders');
|
) setHeaders');
|
||||||
|
hideHeaders = mapAttrsToList (header: hide: mkIf hide "proxy_hide_header ${xvars.escapeString header};") cfg.headers.hide;
|
||||||
in {
|
in {
|
||||||
xvars.enable = mkIf (cfg.headers.rewriteReferer.enable || (cfg.enable && cfg.upstream != null)) true;
|
xvars = {
|
||||||
|
enable = mkIf cfg.headers.rewriteReferer.enable true;
|
||||||
|
defaults = mkIf cfg.enabled (mapOptionDefaults {
|
||||||
|
proxy_scheme = cfg.parsed.scheme;
|
||||||
|
proxy_host = cfg.parsed.host;
|
||||||
|
proxy_port = toString port;
|
||||||
|
proxy_hostport = hostport;
|
||||||
|
});
|
||||||
|
};
|
||||||
proxy = {
|
proxy = {
|
||||||
enabled = mkOptionDefault (config.proxyPass != null);
|
enabled = mkOptionDefault (config.proxyPass != null);
|
||||||
path = mkIf (hasPrefix "/" name) (mkOptionDefault name);
|
path = mkIf (hasPrefix "/" name) (mkOptionDefault name);
|
||||||
|
|
@ -207,8 +220,8 @@ let
|
||||||
};
|
};
|
||||||
proxyPass = mkIf cfg.enable (mkAlmostOptionDefault (removeSuffix "/" cfg.url + cfg.path));
|
proxyPass = mkIf cfg.enable (mkAlmostOptionDefault (removeSuffix "/" cfg.url + cfg.path));
|
||||||
recommendedProxySettings = mkAlmostOptionDefault (cfg.headers.enableRecommended == "nixpkgs");
|
recommendedProxySettings = mkAlmostOptionDefault (cfg.headers.enableRecommended == "nixpkgs");
|
||||||
extraConfig = mkIf cfg.enabled (mkMerge [
|
extraConfig = mkIf cfg.enabled (mkMerge ([
|
||||||
(mkIf (virtualHost.xvars.enable) (mkJustBefore initProxyVars))
|
(mkIf virtualHost.xvars.enable (mkJustBefore initProxyVars))
|
||||||
(mkIf (cfg.headers.rewriteReferer.enable) (mkJustBefore rewriteReferer))
|
(mkIf (cfg.headers.rewriteReferer.enable) (mkJustBefore rewriteReferer))
|
||||||
(mkIf (cfg.redirect.enable) (mkBefore redirect))
|
(mkIf (cfg.redirect.enable) (mkBefore redirect))
|
||||||
(mkIf (emitHeaders) (mkJustAfter setHeaders))
|
(mkIf (emitHeaders) (mkJustAfter setHeaders))
|
||||||
|
|
@ -216,17 +229,18 @@ let
|
||||||
(mkIf (cfg.ssl.enabled && cfg.ssl.host != null) "proxy_ssl_name ${cfg.ssl.host};")
|
(mkIf (cfg.ssl.enabled && cfg.ssl.host != null) "proxy_ssl_name ${cfg.ssl.host};")
|
||||||
(mkIf (cfg.ssl.enabled && cfg.ssl.verify) "proxy_ssl_verify on;")
|
(mkIf (cfg.ssl.enabled && cfg.ssl.verify) "proxy_ssl_verify on;")
|
||||||
(mkIf cfg.websocket.enable "proxy_cache_bypass $http_upgrade;")
|
(mkIf cfg.websocket.enable "proxy_cache_bypass $http_upgrade;")
|
||||||
]);
|
] ++ hideHeaders));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
hostModule = { config, nixosConfig, gensokyo-zone, lib, ... }: let
|
hostModule = { config, nixosConfig, gensokyo-zone, lib, ... }: let
|
||||||
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults;
|
inherit (gensokyo-zone.lib) mapOptionDefaults mapAlmostOptionDefaults;
|
||||||
inherit (lib.options) mkOption mkEnableOption;
|
inherit (lib.options) mkOption mkEnableOption;
|
||||||
inherit (lib.modules) mkIf mkMerge;
|
inherit (lib.modules) mkIf mkOptionDefault;
|
||||||
inherit (lib.attrsets) attrValues;
|
inherit (lib.attrsets) attrValues;
|
||||||
inherit (lib.lists) any;
|
inherit (lib.lists) any;
|
||||||
inherit (nixosConfig.services) nginx;
|
inherit (nixosConfig.services) nginx;
|
||||||
cfg = config.proxy;
|
cfg = config.proxy;
|
||||||
|
anyLocations = f: any (loc: loc.enable && f loc) (attrValues config.locations);
|
||||||
in {
|
in {
|
||||||
options = with lib.types; {
|
options = with lib.types; {
|
||||||
proxy = {
|
proxy = {
|
||||||
|
|
@ -270,7 +284,15 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
xvars.parseReferer = mkIf (any needsReferer (attrValues config.locations)) true;
|
xvars = {
|
||||||
|
parseReferer = mkIf (anyLocations needsReferer) true;
|
||||||
|
defaults = mkIf (anyLocations (loc: loc.proxy.enabled)) (mkOptionDefault (mapOptionDefaults rec {
|
||||||
|
proxy_scheme = null;
|
||||||
|
proxy_host = "$proxy_host";
|
||||||
|
proxy_port = "$proxy_port";
|
||||||
|
proxy_hostport = "${proxy_host}:${proxy_port}";
|
||||||
|
}));
|
||||||
|
};
|
||||||
proxy = mkIf (cfg.copyFromVhost != null) confCopy;
|
proxy = mkIf (cfg.copyFromVhost != null) confCopy;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,48 @@
|
||||||
let
|
let
|
||||||
locationModule = { config, virtualHost, lib, ... }: let
|
locationModule = { config, virtualHost, lib, ... }: let
|
||||||
inherit (lib.options) mkEnableOption;
|
inherit (lib.options) mkEnableOption mkOption;
|
||||||
|
inherit (lib.attrsets) mapAttrs;
|
||||||
cfg = config.xvars;
|
cfg = config.xvars;
|
||||||
in {
|
in {
|
||||||
options.xvars = with lib.types; {
|
options.xvars = with lib.types; {
|
||||||
enable = mkEnableOption "$x_variables";
|
enable = mkEnableOption "$x_variables";
|
||||||
|
defaults = mkOption {
|
||||||
|
type = attrsOf (nullOr str);
|
||||||
|
default = { };
|
||||||
|
};
|
||||||
|
lib = mkOption {
|
||||||
|
type = attrs;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
config = let
|
config = {
|
||||||
in {
|
xvars = {
|
||||||
|
lib = let
|
||||||
|
xvars = virtualHost.xvars.lib;
|
||||||
|
get = mapAttrs (name: default: if virtualHost.xvars.enable then "$x_${name}" else assert default != null; default) cfg.defaults;
|
||||||
|
in xvars // {
|
||||||
|
get = xvars.get // get;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
_module.args.xvars = config.xvars.lib;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
hostModule = { config, nixosConfig, gensokyo-zone, xvars, lib, ... }: let
|
hostModule = { config, nixosConfig, gensokyo-zone, xvars, lib, ... }: let
|
||||||
inherit (gensokyo-zone.lib) mkJustBefore;
|
inherit (gensokyo-zone.lib) mkJustBefore;
|
||||||
inherit (lib.options) mkOption mkEnableOption;
|
inherit (lib.options) mkOption mkEnableOption;
|
||||||
inherit (lib.modules) mkIf mkMerge mkOptionDefault;
|
inherit (lib.modules) mkIf mkMerge mkOptionDefault;
|
||||||
inherit (lib.strings) concatStringsSep;
|
|
||||||
inherit (lib.attrsets) attrValues filterAttrs mapAttrs mapAttrsToList;
|
inherit (lib.attrsets) attrValues filterAttrs mapAttrs mapAttrsToList;
|
||||||
inherit (lib.lists) any;
|
inherit (lib.lists) any;
|
||||||
|
inherit (lib.strings) concatStringsSep hasPrefix hasInfix;
|
||||||
|
inherit (lib.trivial) isInt;
|
||||||
cfg = config.xvars;
|
cfg = config.xvars;
|
||||||
escapeString = value: if value == "" then ''""'' else toString value;
|
escapeString = value:
|
||||||
|
if value == "" then ''""''
|
||||||
|
else if isInt value then toString value
|
||||||
|
else if hasPrefix ''"'' value || hasPrefix "'" value then value # already escaped, may include trailing arguments
|
||||||
|
else if hasInfix ''"'' value then "'${value}'"
|
||||||
|
else if hasInfix " " value || hasInfix ";" value || hasInfix "'" value then ''"${value}"''
|
||||||
|
else value;
|
||||||
|
anyLocations = f: any (loc: loc.enable && f loc) (attrValues config.locations);
|
||||||
in {
|
in {
|
||||||
options = with lib.types; {
|
options = with lib.types; {
|
||||||
xvars = {
|
xvars = {
|
||||||
|
|
@ -34,10 +58,6 @@ let
|
||||||
host = "$host";
|
host = "$host";
|
||||||
referer = "$http_referer";
|
referer = "$http_referer";
|
||||||
https = "$https";
|
https = "$https";
|
||||||
proxy_host = "$proxy_host";
|
|
||||||
proxy_port = "$proxy_port";
|
|
||||||
proxy_hostport = "${proxy_host}:${proxy_port}";
|
|
||||||
proxy_scheme = null;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
lib = mkOption {
|
lib = mkOption {
|
||||||
|
|
@ -49,7 +69,7 @@ let
|
||||||
modules = [ locationModule ];
|
modules = [ locationModule ];
|
||||||
shorthandOnlyDefinesConfig = true;
|
shorthandOnlyDefinesConfig = true;
|
||||||
specialArgs = {
|
specialArgs = {
|
||||||
inherit nixosConfig gensokyo-zone xvars;
|
inherit nixosConfig gensokyo-zone;
|
||||||
virtualHost = config;
|
virtualHost = config;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
@ -70,7 +90,7 @@ let
|
||||||
in {
|
in {
|
||||||
xvars = {
|
xvars = {
|
||||||
enable = mkMerge [
|
enable = mkMerge [
|
||||||
(mkIf (any (loc: loc.xvars.enable) (attrValues config.locations)) true)
|
(mkIf (anyLocations (loc: loc.xvars.enable)) true)
|
||||||
(mkIf cfg.parseReferer true)
|
(mkIf cfg.parseReferer true)
|
||||||
];
|
];
|
||||||
defaults = mkIf cfg.parseReferer (mkOptionDefault {
|
defaults = mkIf cfg.parseReferer (mkOptionDefault {
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,9 @@ in {
|
||||||
proxy = {
|
proxy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
websocket.enable = true;
|
websocket.enable = true;
|
||||||
|
headers.hide.Access-Control-Allow-Origin = true;
|
||||||
};
|
};
|
||||||
extraConfig = ''
|
headers.set.Access-Control-Allow-Origin = "${xvars.get.scheme}://${virtualHost.serverName}";
|
||||||
proxy_hide_header Access-Control-Allow-Origin;
|
|
||||||
add_header Access-Control-Allow-Origin ${xvars.get.scheme}://${virtualHost.serverName};
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
allLocations = mkMerge [
|
allLocations = mkMerge [
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,10 @@ in {
|
||||||
proxy = {
|
proxy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
websocket.enable = true;
|
websocket.enable = true;
|
||||||
headers.enableRecommended = true;
|
headers.hide.content-security-policy = true;
|
||||||
};
|
};
|
||||||
|
headers.set.content-security-policy = contentSecurityPolicy;
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_hide_header content-security-policy;
|
|
||||||
add_header content-security-policy "${contentSecurityPolicy}";
|
|
||||||
proxy_cookie_domain ${virtualHosts.invidious.serverName} ${xvars.get.host};
|
proxy_cookie_domain ${virtualHosts.invidious.serverName} ${xvars.get.host};
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -16,19 +16,21 @@ with lib; {
|
||||||
recommendedOptimisation = true;
|
recommendedOptimisation = true;
|
||||||
recommendedProxySettings = true;
|
recommendedProxySettings = true;
|
||||||
recommendedTlsSettings = false;
|
recommendedTlsSettings = false;
|
||||||
|
headers.set = {
|
||||||
|
Referrer-Policy = mkDefault "origin-when-cross-origin";
|
||||||
|
#Strict-Transport-Security = "$hsts_header";
|
||||||
|
#Content-Security-Policy = ''"script-src 'self'; object-src 'none'; base-uri 'none';" always'';
|
||||||
|
#X-Frame-Options = "DENY";
|
||||||
|
#X-Content-Type-Options = "nosniff";
|
||||||
|
#X-XSS-Protection = "1; mode=block";
|
||||||
|
};
|
||||||
commonHttpConfig = ''
|
commonHttpConfig = ''
|
||||||
map $scheme $hsts_header {
|
map $scheme $hsts_header {
|
||||||
https "max-age=31536000; includeSubdomains; preload";
|
https "max-age=31536000; includeSubdomains; preload";
|
||||||
}
|
}
|
||||||
#add_header Strict-Transport-Security $hsts_header;
|
|
||||||
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
|
|
||||||
add_header 'Referrer-Policy' 'origin-when-cross-origin';
|
|
||||||
#add_header X-Frame-Options DENY;
|
|
||||||
#add_header X-Content-Type-Options nosniff;
|
|
||||||
#add_header X-XSS-Protection "1; mode=block";
|
|
||||||
#proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
|
#proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
|
||||||
'';
|
'';
|
||||||
clientMaxBodySize = "512m";
|
clientMaxBodySize = mkDefault "512m";
|
||||||
virtualHosts.fallback = {
|
virtualHosts.fallback = {
|
||||||
serverName = null;
|
serverName = null;
|
||||||
default = mkDefault true;
|
default = mkDefault true;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue