mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 04:19: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.strings) splitString toLower;
|
||||||
inherit (nixlib.lists) imap0 elemAt findFirst;
|
inherit (nixlib.lists) imap0 elemAt findFirst;
|
||||||
inherit (nixlib.attrsets) mapAttrs listToAttrs nameValuePair;
|
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;
|
inherit (nixlib.trivial) flip toHexString bitOr;
|
||||||
|
|
||||||
toHexStringLower = v: toLower (toHexString v);
|
toHexStringLower = v: toLower (toHexString v);
|
||||||
|
|
@ -31,6 +31,18 @@
|
||||||
nibble0 + (fixedWidthString 1 "0" (toHexStringLower nibble1));
|
nibble0 + (fixedWidthString 1 "0" (toHexStringLower nibble1));
|
||||||
in "${part0 (part 0)}${part 1}:${part 2}ff:fe${part 3}:${part 4}${part 5}";
|
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]);
|
userIs = group: user: builtins.elem group (user.extraGroups ++ [user.group]);
|
||||||
|
|
||||||
mkWinPath = replaceStrings ["/"] ["\\"];
|
mkWinPath = replaceStrings ["/"] ["\\"];
|
||||||
|
|
@ -51,11 +63,17 @@
|
||||||
mkAlmostOptionDefault = mkOverride overrideAlmostOptionDefault;
|
mkAlmostOptionDefault = mkOverride overrideAlmostOptionDefault;
|
||||||
mkAlmostDefault = mkOverride overrideAlmostDefault;
|
mkAlmostDefault = mkOverride overrideAlmostDefault;
|
||||||
mkAlmostForce = mkOverride overrideAlmostForce;
|
mkAlmostForce = mkOverride overrideAlmostForce;
|
||||||
|
orderJustBefore = 400;
|
||||||
orderBefore = 500;
|
orderBefore = 500;
|
||||||
|
orderAlmostBefore = 600;
|
||||||
orderNone = 1000;
|
orderNone = 1000;
|
||||||
orderAfter = 1500;
|
|
||||||
orderAlmostAfter = 1400;
|
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);
|
mapOverride = priority: mapAttrs (_: mkOverride priority);
|
||||||
mapOptionDefaults = mapOverride overrideOptionDefault;
|
mapOptionDefaults = mapOverride overrideOptionDefault;
|
||||||
mapAlmostOptionDefaults = mapOverride overrideAlmostOptionDefault;
|
mapAlmostOptionDefaults = mapOverride overrideAlmostOptionDefault;
|
||||||
|
|
@ -79,13 +97,13 @@ in {
|
||||||
lib = {
|
lib = {
|
||||||
domain = "gensokyo.zone";
|
domain = "gensokyo.zone";
|
||||||
inherit treeToModulesOutput userIs
|
inherit treeToModulesOutput userIs
|
||||||
eui64 mkWinPath mkBaseDn mkAddress6
|
eui64 parseUrl mkWinPath mkBaseDn mkAddress6
|
||||||
toHexStringLower hexCharToInt
|
toHexStringLower hexCharToInt
|
||||||
mapListToAttrs coalesce
|
mapListToAttrs coalesce
|
||||||
mkAlmostOptionDefault mkAlmostDefault mkAlmostForce mapOverride mapOptionDefaults mapAlmostOptionDefaults mapDefaults
|
mkAlmostOptionDefault mkAlmostDefault mkAlmostForce mapOverride mapOptionDefaults mapAlmostOptionDefaults mapDefaults
|
||||||
overrideOptionDefault overrideAlmostOptionDefault overrideDefault overrideAlmostDefault overrideNone overrideAlmostForce overrideForce overrideVM
|
overrideOptionDefault overrideAlmostOptionDefault overrideDefault overrideAlmostDefault overrideNone overrideAlmostForce overrideForce overrideVM
|
||||||
orderBefore orderNone orderAfter orderAlmostAfter
|
orderJustBefore orderBefore orderAlmostBefore orderNone orderAfter orderAlmostAfter orderJustAfter
|
||||||
mkAlmostAfter;
|
mkJustBefore mkAlmostBefore mkAlmostAfter mkJustAfter;
|
||||||
inherit (inputs.arcexprs.lib) unmerged json;
|
inherit (inputs.arcexprs.lib) unmerged json;
|
||||||
};
|
};
|
||||||
gensokyo-zone = {
|
gensokyo-zone = {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
set ${varPrefix}client 1;
|
set ${varPrefix}client 1;
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
localModule = {config, ...}: let
|
localModule = {config, xvars, ...}: let
|
||||||
cfg = config.local;
|
cfg = config.local;
|
||||||
in {
|
in {
|
||||||
options.local = with lib.types; {
|
options.local = with lib.types; {
|
||||||
|
|
@ -100,7 +100,7 @@
|
||||||
in mkMerge [
|
in mkMerge [
|
||||||
(mkIf cfg.emitDenyGlobal (mkBefore allowDirectives))
|
(mkIf cfg.emitDenyGlobal (mkBefore allowDirectives))
|
||||||
(mkIf cfg.emitVars (mkBefore (mkAddrVar "$remote_addr" "$local_")))
|
(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; {
|
options = with lib.types; {
|
||||||
locations = mkOption {
|
locations = mkOption {
|
||||||
type = attrsOf (submoduleWith {
|
type = attrsOf (submodule [locationModule]);
|
||||||
modules = [locationModule];
|
|
||||||
shorthandOnlyDefinesConfig = true;
|
|
||||||
specialArgs = {
|
|
||||||
virtualHost = config;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -149,13 +143,7 @@
|
||||||
in {
|
in {
|
||||||
options = with lib.types; {
|
options = with lib.types; {
|
||||||
services.nginx.virtualHosts = mkOption {
|
services.nginx.virtualHosts = mkOption {
|
||||||
type = attrsOf (submoduleWith {
|
type = attrsOf (submodule [hostModule]);
|
||||||
modules = [hostModule];
|
|
||||||
shorthandOnlyDefinesConfig = true;
|
|
||||||
specialArgs = {
|
|
||||||
nixosConfig = config;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,27 @@
|
||||||
{
|
{
|
||||||
config,
|
|
||||||
lib,
|
lib,
|
||||||
inputs,
|
inputs,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
inherit (inputs.self.lib.lib) mkAlmostAfter mkAlmostOptionDefault;
|
inherit (inputs.self.lib.lib) mkJustBefore mkAlmostOptionDefault orderJustBefore;
|
||||||
inherit (lib.options) mkOption mkEnableOption;
|
inherit (lib.options) mkOption;
|
||||||
inherit (lib.modules) mkIf mkMerge mkBefore mkDefault mkOptionDefault;
|
inherit (lib.modules) mkIf mkMerge mkOrder mkDefault mkOptionDefault;
|
||||||
inherit (lib.strings) optionalString splitString match;
|
xHeadersProxied = { xvars }: ''
|
||||||
inherit (lib.attrsets) attrValues;
|
${xvars.init "forwarded_for" "$proxy_add_x_forwarded_for"}
|
||||||
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;
|
|
||||||
if ($http_x_forwarded_proto) {
|
if ($http_x_forwarded_proto) {
|
||||||
set $x_scheme $http_x_forwarded_proto;
|
${xvars.init "scheme" "$http_x_forwarded_proto"}
|
||||||
}
|
}
|
||||||
if ($http_x_real_ip) {
|
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) {
|
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) {
|
if ($http_x_forwarded_server) {
|
||||||
set $x_forwarded_server $http_x_forwarded_server;
|
${xvars.init "forwarded_server" "$http_x_forwarded_server"}
|
||||||
}
|
|
||||||
if ($x_referer ~ "^https?://([^/]*)/(.*)$") {
|
|
||||||
set $x_referer_host $1;
|
|
||||||
set $x_referer_path $2;
|
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
locationModule = { config, virtualHost, ... }: let
|
locationModule = { config, virtualHost, xvars, ... }: let
|
||||||
cfg = config.proxied;
|
cfg = config.proxied;
|
||||||
in {
|
in {
|
||||||
options = with lib.types; {
|
options = with lib.types; {
|
||||||
|
|
@ -64,94 +34,30 @@
|
||||||
type = bool;
|
type = bool;
|
||||||
readOnly = true;
|
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
|
config = let
|
||||||
emitVars = cfg.enabled && !virtualHost.proxied.enabled;
|
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 {
|
in {
|
||||||
proxied = {
|
proxied = {
|
||||||
enabled = mkOptionDefault (virtualHost.proxied.enabled || cfg.enable != false);
|
enabled = mkOptionDefault (virtualHost.proxied.enabled || cfg.enable != false);
|
||||||
xvars.enable = mkIf (cfg.enabled || emitRedirectScheme || emitHeaders) true;
|
|
||||||
};
|
};
|
||||||
proxy = {
|
proxy = {
|
||||||
enabled = mkOptionDefault (config.proxyPass != null);
|
headers = {
|
||||||
headers.enableRecommended = mkOptionDefault (
|
enableRecommended = mkIf cfg.enabled (mkAlmostOptionDefault true);
|
||||||
if !virtualHost.recommendedProxySettings then false
|
rewriteReferer.enable = mkIf cfg.enabled (mkAlmostOptionDefault true);
|
||||||
else if cfg.enabled then true
|
};
|
||||||
else "nixpkgs"
|
redirect.enable = mkIf cfg.enabled (mkAlmostOptionDefault true);
|
||||||
);
|
|
||||||
scheme = mkOptionDefault (
|
|
||||||
mapNullable schemeForUrl config.proxyPass
|
|
||||||
);
|
|
||||||
path = mkOptionDefault (
|
|
||||||
mapNullable pathForUrl config.proxyPass
|
|
||||||
);
|
|
||||||
host = mkOptionDefault (
|
|
||||||
mapNullable hostForUrl config.proxyPass
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
recommendedProxySettings = mkMerge [
|
xvars.enable = mkIf cfg.enabled true;
|
||||||
(mkAlmostOptionDefault (config.proxy.headers.enableRecommended == "nixpkgs"))
|
|
||||||
];
|
|
||||||
extraConfig = mkMerge [
|
extraConfig = mkMerge [
|
||||||
(mkIf emitVars (
|
(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;
|
cfg = config.proxied;
|
||||||
in {
|
in {
|
||||||
options = with lib.types; {
|
options = with lib.types; {
|
||||||
|
|
@ -164,13 +70,6 @@
|
||||||
type = bool;
|
type = bool;
|
||||||
default = cfg.enable != false;
|
default = cfg.enable != false;
|
||||||
};
|
};
|
||||||
xvars.enable = mkEnableOption "$x_variables" // {
|
|
||||||
default = cfg.enabled;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
recommendedProxySettings = mkOption {
|
|
||||||
type = bool;
|
|
||||||
default = nginx.recommendedProxySettings;
|
|
||||||
};
|
};
|
||||||
locations = mkOption {
|
locations = mkOption {
|
||||||
type = attrsOf (submoduleWith {
|
type = attrsOf (submoduleWith {
|
||||||
|
|
@ -181,23 +80,17 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
proxied = {
|
xvars.enable = mkIf cfg.enabled true;
|
||||||
xvars.enable = mkIf (any (loc: loc.proxied.xvars.enable) (attrValues config.locations)) true;
|
|
||||||
};
|
|
||||||
local.denyGlobal = mkIf (cfg.enable == "cloudflared") (mkDefault true);
|
local.denyGlobal = mkIf (cfg.enable == "cloudflared") (mkDefault true);
|
||||||
extraConfig = mkIf cfg.xvars.enable (mkBefore ''
|
extraConfig = mkIf (cfg.enabled && config.xvars.enable) (
|
||||||
${xHeadersDefaults}
|
mkOrder (orderJustBefore + 25) (xHeadersProxied { inherit xvars; })
|
||||||
${optionalString cfg.enabled xHeadersProxied}
|
);
|
||||||
'');
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
options = with lib.types; {
|
options = with lib.types; {
|
||||||
services.nginx.virtualHosts = mkOption {
|
services.nginx.virtualHosts = mkOption {
|
||||||
type = attrsOf (submoduleWith {
|
type = attrsOf (submodule [hostModule]);
|
||||||
modules = [ hostModule ];
|
|
||||||
shorthandOnlyDefinesConfig = true;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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.attrsets) mapAttrsToList;
|
||||||
inherit (lib.trivial) warnIf;
|
inherit (lib.trivial) warnIf;
|
||||||
inherit (config.services) nginx;
|
inherit (config.services) nginx;
|
||||||
forceRedirectConfig = virtualHost: ''
|
forceRedirectConfig = virtualHost: let
|
||||||
if ($x_scheme = http) {
|
xvars = virtualHost.xvars.lib;
|
||||||
return ${toString virtualHost.redirectCode} https://$x_forwarded_host$request_uri;
|
in ''
|
||||||
|
if (${xvars.get.scheme} = http) {
|
||||||
|
return ${toString virtualHost.redirectCode} https://${xvars.get.host}$request_uri;
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
locationModule = { config, virtualHost, ... }: let
|
locationModule = { config, virtualHost, ... }: let
|
||||||
|
|
@ -23,7 +25,7 @@
|
||||||
force = mkEnableOption "redirect to SSL";
|
force = mkEnableOption "redirect to SSL";
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
proxied.xvars.enable = mkIf emitForce true;
|
xvars.enable = mkIf emitForce true;
|
||||||
extraConfig = mkIf emitForce (forceRedirectConfig virtualHost);
|
extraConfig = mkIf emitForce (forceRedirectConfig virtualHost);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -119,7 +121,7 @@
|
||||||
sslCertificate = mkIf (cfg.cert.path != null) (mkAlmostOptionDefault cfg.cert.path);
|
sslCertificate = mkIf (cfg.cert.path != null) (mkAlmostOptionDefault cfg.cert.path);
|
||||||
sslCertificateKey = mkIf (cfg.cert.keyPath != null) (mkAlmostOptionDefault cfg.cert.keyPath);
|
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);
|
extraConfig = mkIf emitForce (forceRedirectConfig config);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@
|
||||||
inherit (lib.options) mkOption mkEnableOption;
|
inherit (lib.options) mkOption mkEnableOption;
|
||||||
inherit (lib.modules) mkIf mkMerge mkBefore mkAfter mkOptionDefault;
|
inherit (lib.modules) mkIf mkMerge mkBefore mkAfter mkOptionDefault;
|
||||||
inherit (lib.attrsets) mapAttrsToList;
|
inherit (lib.attrsets) mapAttrsToList;
|
||||||
inherit (lib.strings) toLower replaceStrings;
|
inherit (lib.strings) toLower replaceStrings removePrefix;
|
||||||
inherit (config) networking;
|
inherit (config) networking;
|
||||||
inherit (config.services) vouch-proxy nginx tailscale;
|
inherit (config.services) vouch-proxy nginx tailscale;
|
||||||
inherit (nginx) vouch;
|
inherit (nginx) vouch;
|
||||||
locationModule = {config, virtualHost, ...}: {
|
locationModule = {config, virtualHost, xvars, ...}: {
|
||||||
options.vouch = with lib.types; {
|
options.vouch = with lib.types; {
|
||||||
requireAuth = mkEnableOption "require auth to access this location";
|
requireAuth = mkEnableOption "require auth to access this location";
|
||||||
setProxyHeader = mkOption {
|
setProxyHeader = mkOption {
|
||||||
|
|
@ -33,20 +33,19 @@
|
||||||
(mkBefore virtualHost.vouch.auth.lua.accessLogic)
|
(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 [
|
extraConfig = assert virtualHost.vouch.enable; mkMerge [
|
||||||
(mkIf (!virtualHost.vouch.requireAuth) virtualHost.vouch.auth.requestDirective)
|
(mkIf (!virtualHost.vouch.requireAuth) virtualHost.vouch.auth.requestDirective)
|
||||||
(allowOrigin vouch.url)
|
(allowOrigin vouch.url)
|
||||||
(allowOrigin vouch.authUrl)
|
(allowOrigin vouch.authUrl)
|
||||||
(mkIf enableVouchLocal (allowOrigin vouch.localUrl))
|
(mkIf enableVouchLocal (allowOrigin vouch.localUrl))
|
||||||
(mkIf enableVouchTail (allowOrigin "$x_scheme://${vouch.tailDomain}"))
|
(mkIf enableVouchLocal (allowOrigin "sso.local.${networking.domain}"))
|
||||||
(mkIf config.vouch.setProxyHeader ''
|
(mkIf enableVouchTail (allowOrigin "${xvars.get.scheme}://${vouch.tailDomain}"))
|
||||||
proxy_set_header X-Vouch-User $auth_resp_x_vouch_user;
|
|
||||||
'')
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
hostModule = {config, ...}: let
|
hostModule = {config, xvars, ...}: let
|
||||||
cfg = config.vouch;
|
cfg = config.vouch;
|
||||||
mkHeaderVar = header: toLower (replaceStrings [ "-" ] [ "_" ] header);
|
mkHeaderVar = header: toLower (replaceStrings [ "-" ] [ "_" ] header);
|
||||||
mkUpstreamVar = header: "\$upstream_http_${mkHeaderVar 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
|
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 vouch_url = ngx.var["vouch_url"] or "${vouch.url}"
|
||||||
local query_args = ngx.encode_args {
|
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 "",
|
["X-Vouch-Token"] = ngx.ctx.auth_res.header["X-Vouch-Token"] or "",
|
||||||
error = ngx.ctx.auth_res.header["X-Vouch-Error"] or "",
|
error = ngx.ctx.auth_res.header["X-Vouch-Error"] or "",
|
||||||
-- ["vouch-failcount"] is now a session variable and shouldn't be needed anymore
|
-- ["vouch-failcount"] is now a session variable and shouldn't be needed anymore
|
||||||
|
|
@ -145,13 +144,13 @@
|
||||||
};
|
};
|
||||||
extraConfig = let
|
extraConfig = let
|
||||||
localVouchUrl = ''
|
localVouchUrl = ''
|
||||||
if ($x_forwarded_host ~ "\.local\.${networking.domain}$") {
|
if (${xvars.get.host} ~ "\.local\.${networking.domain}$") {
|
||||||
set $vouch_url ${vouch.localUrl};
|
set $vouch_url ${vouch.localUrl};
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
tailVouchUrl = ''
|
tailVouchUrl = ''
|
||||||
if ($x_forwarded_host ~ "\.tail\.${networking.domain}$") {
|
if (${xvars.get.host} ~ "\.tail\.${networking.domain}$") {
|
||||||
set $vouch_url $x_scheme://${vouch.tailDomain};
|
set $vouch_url ${xvars.get.scheme}://${vouch.tailDomain};
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
setVouchUrl = [
|
setVouchUrl = [
|
||||||
|
|
@ -170,33 +169,32 @@
|
||||||
mkBefore "auth_request_set \$${authVar} ${mkUpstreamVar header};"
|
mkBefore "auth_request_set \$${authVar} ${mkUpstreamVar header};"
|
||||||
)) cfg.auth.variables
|
)) cfg.auth.variables
|
||||||
));
|
));
|
||||||
proxied.xvars.enable = mkIf cfg.enable true;
|
xvars.enable = mkIf cfg.enable true;
|
||||||
locations = mkIf cfg.enable {
|
locations = mkIf cfg.enable {
|
||||||
"/" = mkIf cfg.requireAuth {
|
"/" = mkIf cfg.requireAuth {
|
||||||
vouch.requireAuth = mkAlmostOptionDefault true;
|
vouch.requireAuth = mkAlmostOptionDefault true;
|
||||||
};
|
};
|
||||||
${cfg.auth.errorLocation} = mkIf (cfg.auth.errorLocation != null) {
|
${cfg.auth.errorLocation} = mkIf (cfg.auth.errorLocation != null) {
|
||||||
proxied.xvars.enable = true;
|
xvars.enable = true;
|
||||||
extraConfig = ''
|
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, ... }: {
|
${cfg.auth.requestLocation} = { config, xvars, ... }: {
|
||||||
proxyPass = "${vouch.proxyOrigin}/validate";
|
proxy = {
|
||||||
proxy.headers.enableRecommended = false;
|
enable = true;
|
||||||
proxied.rewriteReferer = false;
|
url = vouch.proxyOrigin;
|
||||||
extraConfig = let
|
|
||||||
# nginx-proxied vouch must use X-Forwarded-Host, but vanilla vouch requires Host
|
# 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)
|
then (if cfg.localSso.enable then vouch.doubleProxy.localServerName else vouch.doubleProxy.serverName)
|
||||||
else "$x_forwarded_host";
|
else xvars.get.host;
|
||||||
in ''
|
headers = {
|
||||||
proxy_set_header Host ${vouchProxyHost};
|
set.Content-Length = "";
|
||||||
proxy_set_header X-Forwarded-Host $x_forwarded_host;
|
rewriteReferer.enable = false;
|
||||||
proxy_set_header Referer $x_referer;
|
};
|
||||||
proxy_set_header X-Forwarded-Proto $x_scheme;
|
};
|
||||||
|
extraConfig = ''
|
||||||
proxy_pass_request_body off;
|
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;
|
inherit (config.services) barcodebuddy nginx;
|
||||||
name.shortServer = mkDefault "bbuddy";
|
name.shortServer = mkDefault "bbuddy";
|
||||||
serverName = "@bbuddy_internal";
|
serverName = "@bbuddy_internal";
|
||||||
extraConfig = ''
|
|
||||||
set $x_proxy_host ${serverName};
|
|
||||||
'';
|
|
||||||
in {
|
in {
|
||||||
config.services.nginx.virtualHosts = {
|
config.services.nginx.virtualHosts = {
|
||||||
barcodebuddy'php = mkIf barcodebuddy.enable {
|
barcodebuddy'php = mkIf barcodebuddy.enable {
|
||||||
|
|
@ -18,35 +15,44 @@ in {
|
||||||
local.denyGlobal = true;
|
local.denyGlobal = true;
|
||||||
};
|
};
|
||||||
barcodebuddy = {
|
barcodebuddy = {
|
||||||
inherit name extraConfig;
|
inherit name;
|
||||||
vouch = {
|
vouch = {
|
||||||
enable = true;
|
enable = true;
|
||||||
requireAuth = false;
|
requireAuth = false;
|
||||||
};
|
};
|
||||||
|
proxy = {
|
||||||
|
url = mkIf barcodebuddy.enable (mkDefault
|
||||||
|
"http://localhost:${toString nginx.defaultHTTPListenPort}"
|
||||||
|
);
|
||||||
|
host = mkDefault serverName;
|
||||||
|
};
|
||||||
locations = {
|
locations = {
|
||||||
"/api/" = {
|
"/api/" = {
|
||||||
proxy.headers.enableRecommended = true;
|
proxy.enable = true;
|
||||||
proxyPass = mkDefault "${nginx.virtualHosts.barcodebuddy.locations."/".proxyPass}/api/";
|
|
||||||
};
|
};
|
||||||
"/" = {
|
"/" = {
|
||||||
proxy.headers.enableRecommended = true;
|
proxy.enable = true;
|
||||||
vouch.requireAuth = true;
|
vouch.requireAuth = true;
|
||||||
proxyPass = mkIf barcodebuddy.enable (mkDefault
|
|
||||||
"http://localhost:${toString nginx.defaultHTTPListenPort}"
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
barcodebuddy'local = {
|
barcodebuddy'local = {
|
||||||
inherit name extraConfig;
|
inherit name;
|
||||||
ssl.cert.copyFromVhost = "barcodebuddy";
|
ssl.cert.copyFromVhost = "barcodebuddy";
|
||||||
local.enable = mkDefault true;
|
local.enable = mkDefault true;
|
||||||
locations."/" = {
|
proxy = {
|
||||||
proxy.headers.enableRecommended = true;
|
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;
|
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;
|
ssl_verify_client optional_no_ca;
|
||||||
'';
|
'';
|
||||||
locations' = domain: {
|
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;
|
proxyPass = mkDefault access.proxyPass;
|
||||||
recommendedProxySettings = false;
|
recommendedProxySettings = false;
|
||||||
extraConfig = ''
|
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_server_name on;
|
||||||
proxy_ssl_name ${domain};
|
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,
|
lib,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
inherit (lib.modules) mkIf mkDefault;
|
inherit (lib.modules) mkIf mkMerge mkDefault;
|
||||||
inherit (lib.lists) optional;
|
inherit (lib.lists) optional;
|
||||||
inherit (config.services) nginx;
|
inherit (config.services) nginx;
|
||||||
system = access.systemForService "freepbx";
|
system = access.systemForService "freepbx";
|
||||||
|
|
@ -15,38 +15,50 @@ in {
|
||||||
proxyScheme = "https";
|
proxyScheme = "https";
|
||||||
url = access.proxyUrlFor { serviceName = "freepbx"; portName = proxyScheme; };
|
url = access.proxyUrlFor { serviceName = "freepbx"; portName = proxyScheme; };
|
||||||
ucpUrl = access.proxyUrlFor { serviceName = "freepbx"; portName = "ucp-ssl"; };
|
ucpUrl = access.proxyUrlFor { serviceName = "freepbx"; portName = "ucp-ssl"; };
|
||||||
|
ucpPath = "/socket.io";
|
||||||
# TODO: ports.asterisk/asterisk-ssl?
|
# TODO: ports.asterisk/asterisk-ssl?
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_buffer_size 128k;
|
proxy_buffer_size 128k;
|
||||||
proxy_buffers 4 256k;
|
proxy_buffers 4 256k;
|
||||||
proxy_busy_buffers_size 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 = {
|
locations = {
|
||||||
"/" = {
|
"/" = { xvars, ... }: {
|
||||||
proxyPass = mkDefault url;
|
xvars.enable = true;
|
||||||
|
proxy = {
|
||||||
|
enable = true;
|
||||||
|
redirect = {
|
||||||
|
enable = true;
|
||||||
|
fromScheme = xvars.get.proxy_scheme;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
"/socket.io" = {
|
${ucpPath} = { xvars, virtualHost, ... }: {
|
||||||
proxy.websocket.enable = true;
|
proxy = {
|
||||||
proxyPass = mkDefault "${ucpUrl}/socket.io";
|
enable = true;
|
||||||
|
websocket.enable = true;
|
||||||
|
};
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_hide_header Access-Control-Allow-Origin;
|
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";
|
name.shortServer = mkDefault "pbx";
|
||||||
kTLS = mkDefault true;
|
kTLS = mkDefault true;
|
||||||
in {
|
in {
|
||||||
freepbx = {
|
freepbx = {
|
||||||
vouch.enable = mkDefault true;
|
vouch.enable = mkDefault true;
|
||||||
ssl.force = true;
|
ssl.force = true;
|
||||||
inherit name locations extraConfig kTLS;
|
proxy.url = mkDefault url;
|
||||||
|
locations = allLocations;
|
||||||
|
inherit name extraConfig kTLS;
|
||||||
};
|
};
|
||||||
freepbx'ucp = {
|
freepbx'ucp = {
|
||||||
serverName = mkDefault nginx.virtualHosts.freepbx.serverName;
|
serverName = mkDefault nginx.virtualHosts.freepbx.serverName;
|
||||||
|
|
@ -62,12 +74,14 @@ in {
|
||||||
extraParameters = [ "default_server" ];
|
extraParameters = [ "default_server" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
proxy.websocket.enable = true;
|
proxy = {
|
||||||
|
url = mkDefault ucpUrl;
|
||||||
|
websocket.enable = true;
|
||||||
|
};
|
||||||
vouch.enable = mkDefault true;
|
vouch.enable = mkDefault true;
|
||||||
local.denyGlobal = mkDefault nginx.virtualHosts.freepbx.local.denyGlobal;
|
local.denyGlobal = mkDefault nginx.virtualHosts.freepbx.local.denyGlobal;
|
||||||
locations."/socket.io" = {
|
locations = {
|
||||||
inherit (locations."/socket.io") proxy extraConfig;
|
inherit (locations) "/socket.io";
|
||||||
proxyPass = mkDefault nginx.virtualHosts.freepbx.locations."/socket.io".proxyPass;
|
|
||||||
};
|
};
|
||||||
inherit extraConfig kTLS;
|
inherit extraConfig kTLS;
|
||||||
};
|
};
|
||||||
|
|
@ -84,16 +98,9 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ssl.cert.copyFromVhost = "freepbx";
|
ssl.cert.copyFromVhost = "freepbx";
|
||||||
|
proxy.url = mkDefault nginx.virtualHosts.freepbx.proxy.url;
|
||||||
local.enable = true;
|
local.enable = true;
|
||||||
locations = {
|
locations = allLocations;
|
||||||
"/" = {
|
|
||||||
proxyPass = mkDefault nginx.virtualHosts.freepbx.locations."/".proxyPass;
|
|
||||||
};
|
|
||||||
"/socket.io" = {
|
|
||||||
inherit (locations."/socket.io") proxy extraConfig;
|
|
||||||
proxyPass = mkDefault nginx.virtualHosts.freepbx.locations."/socket.io".proxyPass;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
inherit name extraConfig kTLS;
|
inherit name extraConfig kTLS;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,25 +3,24 @@
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
inherit (lib.modules) mkIf mkMerge mkDefault;
|
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
|
||||||
inherit (lib.strings) escapeRegex;
|
inherit (lib.strings) removePrefix escapeRegex;
|
||||||
inherit (config.services) grocy nginx;
|
inherit (config.services) grocy nginx;
|
||||||
inherit (config) networking;
|
inherit (config) networking;
|
||||||
name.shortServer = mkDefault "grocy";
|
name.shortServer = mkDefault "grocy";
|
||||||
serverName = "@grocy_internal";
|
serverName = "@grocy_internal";
|
||||||
serverName'local = "@grocy_internal_local";
|
serverName'local = "@grocy_internal_local";
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
set $x_proxy_host ${serverName};
|
|
||||||
set $grocy_user "";
|
set $grocy_user "";
|
||||||
'';
|
'';
|
||||||
location = {
|
locations."/" = {
|
||||||
vouch.setProxyHeader = true;
|
vouch.setProxyHeader = true;
|
||||||
proxy.headers.enableRecommended = true;
|
proxy = {
|
||||||
extraConfig = ''
|
enable = true;
|
||||||
proxy_set_header X-Grocy-User $grocy_user;
|
headers.set.X-Grocy-User = mkOptionDefault "$grocy_user";
|
||||||
'';
|
};
|
||||||
};
|
};
|
||||||
luaAuthHost = { config, ... }: {
|
luaAuthHost = { config, xvars, ... }: {
|
||||||
vouch.auth.lua = {
|
vouch.auth.lua = {
|
||||||
enable = true;
|
enable = true;
|
||||||
accessRequest = ''
|
accessRequest = ''
|
||||||
|
|
@ -34,7 +33,7 @@
|
||||||
status = ngx.HTTP_OK,
|
status = ngx.HTTP_OK,
|
||||||
header = { },
|
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 = {
|
-- ngx.ctx.auth_res = {
|
||||||
-- status = ngx.HTTP_OK,
|
-- status = ngx.HTTP_OK,
|
||||||
-- header = { },
|
-- header = { },
|
||||||
|
|
@ -54,35 +53,40 @@ in {
|
||||||
inherit serverName;
|
inherit serverName;
|
||||||
};
|
};
|
||||||
grocy = mkMerge [ luaAuthHost {
|
grocy = mkMerge [ luaAuthHost {
|
||||||
inherit name extraConfig;
|
inherit name extraConfig locations;
|
||||||
vouch.enable = true;
|
vouch.enable = true;
|
||||||
locations."/" = mkMerge [ location {
|
proxy = {
|
||||||
proxyPass = mkIf (grocy.enable) (mkDefault
|
url = mkIf grocy.enable (mkDefault
|
||||||
"http://localhost:${toString nginx.defaultHTTPListenPort}"
|
"http://localhost:${toString nginx.defaultHTTPListenPort}"
|
||||||
);
|
);
|
||||||
} ];
|
host = mkDefault serverName;
|
||||||
|
};
|
||||||
} ];
|
} ];
|
||||||
grocy'local = {
|
grocy'local = {
|
||||||
inherit name;
|
inherit name;
|
||||||
local.enable = mkDefault true;
|
local.enable = mkDefault true;
|
||||||
ssl.cert.copyFromVhost = "grocy";
|
ssl.cert.copyFromVhost = "grocy";
|
||||||
locations."/" = {
|
proxy = {
|
||||||
proxy.headers.enableRecommended = true;
|
url = mkDefault "http://localhost:${toString nginx.defaultHTTPListenPort}";
|
||||||
proxyPass = 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 {
|
grocy'local'int = mkMerge [ luaAuthHost {
|
||||||
# internal proxy workaround for http2 lua compat issues
|
# internal proxy workaround for http2 lua compat issues
|
||||||
serverName = serverName'local;
|
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;
|
proxied.enable = true;
|
||||||
vouch.enable = true;
|
vouch = {
|
||||||
locations."/" = mkMerge [ location {
|
enable = true;
|
||||||
proxyPass = mkDefault nginx.virtualHosts.grocy.locations."/".proxyPass;
|
localSso.enable = true;
|
||||||
} ];
|
};
|
||||||
} ];
|
} ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -22,15 +22,17 @@ in {
|
||||||
# Buffering off send to the client as soon as the data is received from invidious.
|
# Buffering off send to the client as soon as the data is received from invidious.
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
set $x_proxy_host $x_forwarded_host;
|
|
||||||
'';
|
'';
|
||||||
location = {
|
location = { xvars, ... }: {
|
||||||
proxy.websocket.enable = true;
|
proxy = {
|
||||||
proxy.headers.enableRecommended = true;
|
enable = true;
|
||||||
|
websocket.enable = true;
|
||||||
|
headers.enableRecommended = true;
|
||||||
|
};
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_hide_header content-security-policy;
|
proxy_hide_header content-security-policy;
|
||||||
add_header content-security-policy "${contentSecurityPolicy}";
|
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";
|
name.shortServer = mkDefault "yt";
|
||||||
|
|
@ -40,20 +42,22 @@ 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 kTLS;
|
inherit name extraConfig kTLS;
|
||||||
locations."/" = {
|
proxy = {
|
||||||
proxyPass = "http://localhost:${toString config.services.nginx.defaultHTTPListenPort}";
|
url = mkDefault "http://localhost:${toString config.services.nginx.defaultHTTPListenPort}";
|
||||||
proxy.headers.enableRecommended = true;
|
host = mkDefault virtualHosts.invidious'int.serverName;
|
||||||
|
};
|
||||||
|
locations."/" = { xvars, ... }: {
|
||||||
|
proxy.enable = true;
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
set $x_proxy_host ${virtualHosts.invidious'int.serverName};
|
set $invidious_req_check ${xvars.get.scheme}:$request_uri;
|
||||||
set $invidious_req_check $x_scheme:$request_uri;
|
|
||||||
if ($invidious_req_check = "http:/") {
|
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";
|
serverName = "@invidious_internal";
|
||||||
proxied.enable = true;
|
proxied.enable = true;
|
||||||
local.denyGlobal = 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 = {
|
locations = {
|
||||||
"/" = mkMerge [
|
"/" = mkMerge [
|
||||||
location
|
location
|
||||||
{
|
{
|
||||||
vouch.requireAuth = true;
|
vouch.requireAuth = true;
|
||||||
proxyPass = mkDefault (if cfg.enable
|
|
||||||
then "http://localhost:${toString cfg.port}"
|
|
||||||
else access.proxyUrlFor { serviceName = "invidious"; }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
inherit extraConfig;
|
inherit extraConfig;
|
||||||
};
|
};
|
||||||
invidious'local = {
|
invidious'local = { xvars, ... }: {
|
||||||
local.enable = true;
|
local.enable = true;
|
||||||
ssl.cert.copyFromVhost = "invidious";
|
ssl.cert.copyFromVhost = "invidious";
|
||||||
locations."/" = mkMerge [
|
proxy = {
|
||||||
location
|
host = mkDefault xvars.get.host;
|
||||||
{
|
url = mkDefault virtualHosts.invidious'int.proxy.url;
|
||||||
proxyPass = mkDefault virtualHosts.invidious'int.locations."/".proxyPass;
|
};
|
||||||
}
|
locations."/" = location;
|
||||||
];
|
|
||||||
inherit name extraConfig kTLS;
|
inherit name extraConfig kTLS;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
}: let
|
}: let
|
||||||
inherit (lib.modules) mkDefault;
|
inherit (lib.modules) mkDefault;
|
||||||
inherit (config.services) nginx;
|
inherit (config.services) nginx;
|
||||||
|
cfg = config.services.unifi;
|
||||||
in {
|
in {
|
||||||
config.services.nginx = {
|
config.services.nginx = {
|
||||||
virtualHosts = let
|
virtualHosts = let
|
||||||
|
|
@ -13,24 +14,34 @@ in {
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
'';
|
'';
|
||||||
|
locations = {
|
||||||
|
"/" = {
|
||||||
|
proxy.enable = true;
|
||||||
|
};
|
||||||
|
"/wss/" = {
|
||||||
|
proxy = {
|
||||||
|
enable = true;
|
||||||
|
websocket.enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
name.shortServer = mkDefault "unifi";
|
name.shortServer = mkDefault "unifi";
|
||||||
kTLS = mkDefault true;
|
kTLS = mkDefault true;
|
||||||
in {
|
in {
|
||||||
unifi = {
|
unifi = {
|
||||||
inherit name extraConfig kTLS;
|
inherit name extraConfig kTLS locations;
|
||||||
vouch.enable = mkDefault true;
|
vouch.enable = mkDefault true;
|
||||||
ssl.force = mkDefault true;
|
ssl.force = mkDefault true;
|
||||||
locations."/" = {
|
proxy.url = mkDefault (if cfg.enable
|
||||||
proxyPass = mkDefault (access.proxyUrlFor { serviceName = "unifi"; portName = "management"; });
|
then "https://localhost:8443"
|
||||||
};
|
else access.proxyUrlFor { serviceName = "unifi"; portName = "management"; }
|
||||||
|
);
|
||||||
};
|
};
|
||||||
unifi'local = {
|
unifi'local = {
|
||||||
inherit name extraConfig kTLS;
|
inherit name extraConfig kTLS locations;
|
||||||
ssl.cert.copyFromVhost = "unifi";
|
ssl.cert.copyFromVhost = "unifi";
|
||||||
local.enable = true;
|
local.enable = true;
|
||||||
locations."/" = {
|
proxy.url = mkDefault nginx.virtualHosts.unifi.proxy.url;
|
||||||
proxyPass = mkDefault nginx.virtualHosts.unifi.locations."/".proxyPass;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,52 +14,51 @@ in {
|
||||||
locations = {
|
locations = {
|
||||||
"/" = {
|
"/" = {
|
||||||
ssl.force = true;
|
ssl.force = true;
|
||||||
|
proxy.enable = true;
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_redirect default;
|
proxy_redirect default;
|
||||||
set $x_proxy_host $x_forwarded_host;
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
"/validate" = {config, virtualHost, ...}: {
|
"/validate" = {config, virtualHost, ...}: {
|
||||||
proxied.enable = true;
|
proxied.enable = true;
|
||||||
proxyPass = mkDefault (virtualHost.locations."/".proxyPass + "/validate");
|
proxy.enable = true;
|
||||||
proxy.headers.enableRecommended = true;
|
|
||||||
local.denyGlobal = true;
|
local.denyGlobal = true;
|
||||||
extraConfig = ''
|
|
||||||
set $x_proxy_host $x_forwarded_host;
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
localLocations = kanidmDomain: mkIf (nginx.vouch.localSso.enable && false) {
|
localLocations = kanidmDomain: mkIf (nginx.vouch.localSso.enable && false) {
|
||||||
"/" = {
|
"/" = { xvars, ... }: {
|
||||||
proxied.xvars.enable = true;
|
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
proxy_redirect https://sso.${networking.domain}/ $x_scheme://${kanidmDomain}/;
|
proxy_redirect https://sso.${networking.domain}/ ${xvars.get.scheme}://${kanidmDomain}/;
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
name.shortServer = mkDefault "login";
|
name.shortServer = mkDefault "login";
|
||||||
in {
|
in {
|
||||||
vouch = {
|
vouch = { xvars, ... }: {
|
||||||
inherit name;
|
inherit name locations;
|
||||||
serverAliases = [ nginx.vouch.doubleProxy.serverName ];
|
serverAliases = [ nginx.vouch.doubleProxy.serverName ];
|
||||||
proxied.enable = true;
|
proxied.enable = true;
|
||||||
|
proxy = {
|
||||||
|
url = mkDefault (
|
||||||
|
access.proxyUrlFor { serviceName = "vouch-proxy"; serviceId = "login"; }
|
||||||
|
);
|
||||||
|
host = mkDefault xvars.get.host;
|
||||||
|
};
|
||||||
local.denyGlobal = true;
|
local.denyGlobal = true;
|
||||||
locations = mkMerge [
|
|
||||||
locations
|
|
||||||
{
|
|
||||||
"/".proxyPass = mkDefault (
|
|
||||||
access.proxyUrlFor { serviceName = "vouch-proxy"; serviceId = "login"; }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
vouch'local = {
|
vouch'local = { xvars, ... }: {
|
||||||
name = {
|
name = {
|
||||||
inherit (name) shortServer;
|
inherit (name) shortServer;
|
||||||
includeTailscale = mkDefault false;
|
includeTailscale = mkDefault false;
|
||||||
};
|
};
|
||||||
serverAliases = mkIf cfg.enable [ nginx.vouch.doubleProxy.localServerName ];
|
serverAliases = mkIf cfg.enable [ nginx.vouch.doubleProxy.localServerName ];
|
||||||
proxied.enable = true;
|
proxied.enable = true;
|
||||||
|
proxy = {
|
||||||
|
url = mkDefault (
|
||||||
|
access.proxyUrlFor { serviceName = "vouch-proxy"; serviceId = "login.local"; }
|
||||||
|
);
|
||||||
|
host = mkDefault xvars.get.host;
|
||||||
|
};
|
||||||
local.enable = true;
|
local.enable = true;
|
||||||
ssl = {
|
ssl = {
|
||||||
force = true;
|
force = true;
|
||||||
|
|
@ -67,15 +66,10 @@ in {
|
||||||
};
|
};
|
||||||
locations = mkMerge [
|
locations = mkMerge [
|
||||||
locations
|
locations
|
||||||
{
|
|
||||||
"/".proxyPass = mkDefault (
|
|
||||||
access.proxyUrlFor { serviceName = "vouch-proxy"; serviceId = "login.local"; }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(localLocations "sso.local.${networking.domain}")
|
(localLocations "sso.local.${networking.domain}")
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
vouch'tail = {
|
vouch'tail = { xvars, ... }: {
|
||||||
enable = mkDefault (tailscale.enable && !nginx.virtualHosts.vouch'local.name.includeTailscale);
|
enable = mkDefault (tailscale.enable && !nginx.virtualHosts.vouch'local.name.includeTailscale);
|
||||||
ssl.cert.copyFromVhost = "vouch'local";
|
ssl.cert.copyFromVhost = "vouch'local";
|
||||||
name = {
|
name = {
|
||||||
|
|
@ -83,11 +77,12 @@ in {
|
||||||
qualifier = mkDefault "tail";
|
qualifier = mkDefault "tail";
|
||||||
};
|
};
|
||||||
local.enable = true;
|
local.enable = true;
|
||||||
|
proxy = {
|
||||||
|
url = mkDefault nginx.virtualHosts.vouch'local.locations."/".proxyPass;
|
||||||
|
host = mkDefault xvars.get.host;
|
||||||
|
};
|
||||||
locations = mkMerge [
|
locations = mkMerge [
|
||||||
locations
|
locations
|
||||||
{
|
|
||||||
"/".proxyPass = mkDefault nginx.virtualHosts.vouch'local.locations."/".proxyPass;
|
|
||||||
}
|
|
||||||
(localLocations "sso.tail.${networking.domain}")
|
(localLocations "sso.tail.${networking.domain}")
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,26 +11,25 @@ in {
|
||||||
EXTERNAL_GROCY_URL = "https://grocy.${config.networking.domain}";
|
EXTERNAL_GROCY_URL = "https://grocy.${config.networking.domain}";
|
||||||
DISABLE_AUTHENTICATION = true;
|
DISABLE_AUTHENTICATION = true;
|
||||||
};
|
};
|
||||||
nginxConfig = mkMerge [
|
nginxConfig = let
|
||||||
|
xvars = nginx.virtualHosts.barcodebuddy'php.xvars.lib;
|
||||||
|
in mkMerge [
|
||||||
''
|
''
|
||||||
include ${config.sops.secrets.barcodebuddy-fastcgi-params.path};
|
include ${config.sops.secrets.barcodebuddy-fastcgi-params.path};
|
||||||
''
|
''
|
||||||
(mkIf cfg.reverseProxy.enable (mkAfter ''
|
(mkIf cfg.reverseProxy.enable (mkAfter ''
|
||||||
set $bbuddy_https "";
|
set $bbuddy_https "";
|
||||||
if ($x_scheme = https) {
|
if (${xvars.get.scheme} = https) {
|
||||||
set $bbuddy_https 1;
|
set $bbuddy_https 1;
|
||||||
}
|
}
|
||||||
fastcgi_param HTTPS $bbuddy_https if_not_empty;
|
fastcgi_param HTTPS $bbuddy_https if_not_empty;
|
||||||
fastcgi_param REQUEST_SCHEME $x_scheme;
|
fastcgi_param REQUEST_SCHEME ${xvars.get.scheme};
|
||||||
fastcgi_param HTTP_HOST $x_forwarded_host;
|
fastcgi_param HTTP_HOST ${xvars.get.host};
|
||||||
''))
|
''))
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
config.services.nginx.virtualHosts.barcodebuddy'php = mkIf cfg.enable {
|
config.services.nginx.virtualHosts.barcodebuddy'php = mkIf cfg.enable {
|
||||||
proxied = {
|
proxied.enable = cfg.reverseProxy.enable;
|
||||||
enable = cfg.reverseProxy.enable;
|
|
||||||
xvars.enable = true;
|
|
||||||
};
|
|
||||||
name.shortServer = mkDefault "bbuddy";
|
name.shortServer = mkDefault "bbuddy";
|
||||||
};
|
};
|
||||||
config.users.users.barcodebuddy = mkIf cfg.enable {
|
config.users.users.barcodebuddy = mkIf cfg.enable {
|
||||||
|
|
|
||||||
|
|
@ -11,58 +11,54 @@ in {
|
||||||
currency = mkDefault "CAD";
|
currency = mkDefault "CAD";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
services.nginx = let
|
services.nginx.virtualHosts = {
|
||||||
extraConfig = mkAfter ''
|
grocy'php = mkIf cfg.enable ({config, xvars, ...}: let
|
||||||
set $grocy_user guest;
|
extraConfig = mkAfter ''
|
||||||
set $grocy_middleware Grocy\Middleware\ReverseProxyAuthMiddleware;
|
set $grocy_user guest;
|
||||||
set $grocy_auth_header GENSO_GROCY_USER;
|
set $grocy_middleware Grocy\Middleware\ReverseProxyAuthMiddleware;
|
||||||
set $grocy_auth_env true;
|
set $grocy_auth_header GENSO_GROCY_USER;
|
||||||
|
set $grocy_auth_env true;
|
||||||
|
|
||||||
if ($http_grocy_api_key) {
|
if ($http_grocy_api_key) {
|
||||||
set $grocy_user "";
|
set $grocy_user "";
|
||||||
}
|
}
|
||||||
if ($request_uri ~ "^/api(/.*|)$") {
|
if ($request_uri ~ "^/api(/.*|)$") {
|
||||||
set $grocy_user "";
|
set $grocy_user "";
|
||||||
}
|
}
|
||||||
if ($http_x_vouch_user ~ "^([^@]+)@.*$") {
|
if ($http_x_vouch_user ~ "^([^@]+)@.*$") {
|
||||||
set $grocy_user $1;
|
set $grocy_user $1;
|
||||||
}
|
}
|
||||||
if ($http_x_grocy_user) {
|
if ($http_x_grocy_user) {
|
||||||
#set $grocy_auth_header X-Grocy-User;
|
#set $grocy_auth_header X-Grocy-User;
|
||||||
#set $grocy_auth_env false;
|
#set $grocy_auth_env false;
|
||||||
set $grocy_user $http_x_grocy_user;
|
set $grocy_user $http_x_grocy_user;
|
||||||
}
|
}
|
||||||
if ($grocy_user = "") {
|
if ($grocy_user = "") {
|
||||||
set $grocy_middleware Grocy\Middleware\DefaultAuthMiddleware;
|
set $grocy_middleware Grocy\Middleware\DefaultAuthMiddleware;
|
||||||
}
|
}
|
||||||
|
|
||||||
fastcgi_param GROCY_AUTH_CLASS $grocy_middleware;
|
fastcgi_param GROCY_AUTH_CLASS $grocy_middleware;
|
||||||
fastcgi_param GROCY_REVERSE_PROXY_AUTH_USE_ENV $grocy_auth_env;
|
fastcgi_param GROCY_REVERSE_PROXY_AUTH_USE_ENV $grocy_auth_env;
|
||||||
fastcgi_param GROCY_REVERSE_PROXY_AUTH_HEADER $grocy_auth_header;
|
fastcgi_param GROCY_REVERSE_PROXY_AUTH_HEADER $grocy_auth_header;
|
||||||
fastcgi_param GENSO_GROCY_USER $grocy_user;
|
fastcgi_param GENSO_GROCY_USER $grocy_user;
|
||||||
|
|
||||||
set $grocy_https "";
|
set $grocy_https "";
|
||||||
if ($x_scheme = https) {
|
if (${xvars.get.scheme} = https) {
|
||||||
set $grocy_https 1;
|
set $grocy_https 1;
|
||||||
}
|
}
|
||||||
fastcgi_param HTTP_HOST $x_forwarded_host;
|
fastcgi_param HTTP_HOST ${xvars.get.host};
|
||||||
fastcgi_param REQUEST_SCHEME $x_scheme;
|
fastcgi_param REQUEST_SCHEME ${xvars.get.scheme};
|
||||||
fastcgi_param HTTPS $grocy_https if_not_empty;
|
fastcgi_param HTTPS $grocy_https if_not_empty;
|
||||||
'';
|
'';
|
||||||
in {
|
in {
|
||||||
virtualHosts = {
|
name.shortServer = mkDefault "grocy";
|
||||||
grocy'php = mkIf cfg.enable ({config, ...}: {
|
proxied.enable = true;
|
||||||
name.shortServer = mkDefault "grocy";
|
xvars.enable = true;
|
||||||
proxied = {
|
local.denyGlobal = true;
|
||||||
enable = true;
|
locations."~ \\.php$" = {
|
||||||
xvars.enable = true;
|
inherit extraConfig;
|
||||||
};
|
};
|
||||||
local.denyGlobal = true;
|
});
|
||||||
locations."~ \\.php$" = {
|
|
||||||
inherit extraConfig;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
users.users.grocy = mkIf cfg.enable {
|
users.users.grocy = mkIf cfg.enable {
|
||||||
uid = 911;
|
uid = 911;
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ in {
|
||||||
services.vouch-proxy = {
|
services.vouch-proxy = {
|
||||||
authUrl = "https://${virtualHosts.keycloak'local.serverName}/realms/${config.networking.domain}";
|
authUrl = "https://${virtualHosts.keycloak'local.serverName}/realms/${config.networking.domain}";
|
||||||
domain = "login.local.${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 = {
|
security.acme.certs = {
|
||||||
|
|
@ -257,13 +257,13 @@ in {
|
||||||
# not the real grocy record-holder, so don't respond globally..
|
# not the real grocy record-holder, so don't respond globally..
|
||||||
local.denyGlobal = true;
|
local.denyGlobal = true;
|
||||||
ssl.cert.enable = true;
|
ssl.cert.enable = true;
|
||||||
locations."/".proxyPass = "http://${mkAddress6 (access.getAddressFor "tei" "lan")}";
|
proxy.url = "http://${mkAddress6 (access.getAddressFor "tei" "lan")}";
|
||||||
};
|
};
|
||||||
barcodebuddy = {
|
barcodebuddy = {
|
||||||
# not the real bbuddy record-holder, so don't respond globally..
|
# not the real bbuddy record-holder, so don't respond globally..
|
||||||
local.denyGlobal = true;
|
local.denyGlobal = true;
|
||||||
ssl.cert.enable = true;
|
ssl.cert.enable = true;
|
||||||
locations."/".proxyPass = "http://${mkAddress6 (access.getAddressFor "tei" "lan")}";
|
proxy.url = "http://${mkAddress6 (access.getAddressFor "tei" "lan")}";
|
||||||
};
|
};
|
||||||
freepbx = {
|
freepbx = {
|
||||||
ssl.cert.enable = true;
|
ssl.cert.enable = true;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue