mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 12:29:19 -08:00
refactor(nginx): proxy options
This commit is contained in:
parent
c3f3fe1fed
commit
02508ecbd3
18 changed files with 638 additions and 424 deletions
32
lib.nix
32
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 = {
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
214
modules/nixos/nginx/proxy.nix
Normal file
214
modules/nixos/nginx/proxy.nix
Normal file
|
|
@ -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]);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -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);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 "";
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
};
|
||||
}
|
||||
110
modules/nixos/nginx/xvars.nix
Normal file
110
modules/nixos/nginx/xvars.nix
Normal file
|
|
@ -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;
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -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/;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
} ];
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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}")
|
||||
];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue